From aaec10f7298a3fcbaaf0bf5c5c3317a710223eb9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:03:12 -0400 Subject: [PATCH 001/120] Revert "Add Orderbook Mid Price Cache (#2289)" (backport #2333) (#2334) Co-authored-by: Adam Fraser --- .../caches/orderbook-mid-prices-cache.test.ts | 106 ----------------- .../src/caches/orderbook-mid-prices-cache.ts | 107 ------------------ indexer/packages/redis/src/caches/scripts.ts | 4 - indexer/packages/redis/src/index.ts | 1 - .../redis/src/scripts/add_market_price.lua | 17 --- .../src/scripts/get_market_median_price.lua | 23 ---- .../__tests__/lib/candles-generator.test.ts | 53 ++++----- .../ender/src/lib/candles-generator.ts | 6 +- .../tasks/cache-orderbook-mid-prices.test.ts | 98 ---------------- indexer/services/roundtable/src/config.ts | 4 - indexer/services/roundtable/src/index.ts | 9 -- .../src/tasks/cache-orderbook-mid-prices.ts | 40 ------- 12 files changed, 30 insertions(+), 438 deletions(-) delete mode 100644 indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts delete mode 100644 indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts delete mode 100644 indexer/packages/redis/src/scripts/add_market_price.lua delete mode 100644 indexer/packages/redis/src/scripts/get_market_median_price.lua delete mode 100644 indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts delete mode 100644 indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts diff --git a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts deleted file mode 100644 index 70ed134e67..0000000000 --- a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { deleteAllAsync } from '../../src/helpers/redis'; -import { redis as client } from '../helpers/utils'; -import { - setPrice, - getMedianPrice, - ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX, -} from '../../src/caches/orderbook-mid-prices-cache'; - -describe('orderbook-mid-prices-cache', () => { - const ticker: string = 'BTC-USD'; - - beforeEach(async () => { - await deleteAllAsync(client); - }); - - afterEach(async () => { - await deleteAllAsync(client); - }); - - describe('setPrice', () => { - it('sets a price for a ticker', async () => { - await setPrice(client, ticker, '50000'); - - await client.zrange( - `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, - 0, - -1, - (_: any, response: string[]) => { - expect(response[0]).toBe('50000'); - }, - ); - }); - - it('sets multiple prices for a ticker', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - ]); - - await client.zrange( - `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, - 0, - -1, - (_: any, response: string[]) => { - expect(response).toEqual(['49000', '50000', '51000']); - }, - ); - }); - }); - - describe('getMedianPrice', () => { - it('returns null when no prices are set', async () => { - const result = await getMedianPrice(client, ticker); - expect(result).toBeNull(); - }); - - it('returns the median price for odd number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - ]); - - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50000'); - }); - - it('returns the median price for even number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - setPrice(client, ticker, '52000'), - ]); - - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50500'); - }); - - it('returns the correct median price after 5 seconds', async () => { - jest.useFakeTimers(); - - const nowSeconds = Math.floor(Date.now() / 1000); - jest.setSystemTime(nowSeconds * 1000); - - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - ]); - - jest.advanceTimersByTime(6000); // Advance time by 6 seconds - await Promise.all([ - setPrice(client, ticker, '49000'), - setPrice(client, ticker, '48000'), - setPrice(client, ticker, '52000'), - setPrice(client, ticker, '53000'), - ]); - - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50500'); - - jest.useRealTimers(); - }); - }); -}); diff --git a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts deleted file mode 100644 index f2857b70e9..0000000000 --- a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Callback, RedisClient } from 'redis'; - -import { - addMarketPriceScript, - getMarketMedianScript, -} from './scripts'; - -// Cache of orderbook prices for each clob pair -// Each price is cached for a 5 second window and in a ZSET -export const ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX: string = 'v4/orderbook_mid_prices/'; - -/** - * Generates a cache key for a given ticker's orderbook mid price. - * @param ticker The ticker symbol - * @returns The cache key string - */ -function getOrderbookMidPriceCacheKey(ticker: string): string { - return `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`; -} - -/** - * Adds a price to the market prices cache for a given ticker. - * Uses a Lua script to add the price with a timestamp to a sorted set in Redis. - * @param client The Redis client - * @param ticker The ticker symbol - * @param price The price to be added - * @returns A promise that resolves when the operation is complete - */ -export async function setPrice( - client: RedisClient, - ticker: string, - price: string, -): Promise { - // Number of keys for the lua script. - const numKeys: number = 1; - - let evalAsync: ( - marketCacheKey: string, - ) => Promise = (marketCacheKey) => { - - return new Promise((resolve, reject) => { - const callback: Callback = ( - err: Error | null, - ) => { - if (err) { - return reject(err); - } - return resolve(); - }; - - const nowSeconds = Math.floor(Date.now() / 1000); // Current time in seconds - client.evalsha( - addMarketPriceScript.hash, - numKeys, - marketCacheKey, - price, - nowSeconds, - callback, - ); - - }); - }; - evalAsync = evalAsync.bind(client); - - return evalAsync( - getOrderbookMidPriceCacheKey(ticker), - ); -} - -/** - * Retrieves the median price for a given ticker from the cache. - * Uses a Lua script to calculate the median price from the sorted set in Redis. - * @param client The Redis client - * @param ticker The ticker symbol - * @returns A promise that resolves with the median price as a string, or null if not found - */ -export async function getMedianPrice(client: RedisClient, ticker: string): Promise { - let evalAsync: ( - marketCacheKey: string, - ) => Promise = ( - marketCacheKey, - ) => { - return new Promise((resolve, reject) => { - const callback: Callback = ( - err: Error | null, - results: string, - ) => { - if (err) { - return reject(err); - } - return resolve(results); - }; - - client.evalsha( - getMarketMedianScript.hash, - 1, - marketCacheKey, - callback, - ); - }); - }; - evalAsync = evalAsync.bind(client); - - return evalAsync( - getOrderbookMidPriceCacheKey(ticker), - ); -} diff --git a/indexer/packages/redis/src/caches/scripts.ts b/indexer/packages/redis/src/caches/scripts.ts index f4f74bffd5..3e1032c6f2 100644 --- a/indexer/packages/redis/src/caches/scripts.ts +++ b/indexer/packages/redis/src/caches/scripts.ts @@ -63,8 +63,6 @@ export const removeOrderScript: LuaScript = newLuaScript('removeOrder', '../scri export const addCanceledOrderIdScript: LuaScript = newLuaScript('addCanceledOrderId', '../scripts/add_canceled_order_id.lua'); export const addStatefulOrderUpdateScript: LuaScript = newLuaScript('addStatefulOrderUpdate', '../scripts/add_stateful_order_update.lua'); export const removeStatefulOrderUpdateScript: LuaScript = newLuaScript('removeStatefulOrderUpdate', '../scripts/remove_stateful_order_update.lua'); -export const addMarketPriceScript: LuaScript = newLuaScript('addMarketPrice', '../scripts/add_market_price.lua'); -export const getMarketMedianScript: LuaScript = newLuaScript('getMarketMedianPrice', '../scripts/get_market_median_price.lua'); export const allLuaScripts: LuaScript[] = [ deleteZeroPriceLevelScript, @@ -77,6 +75,4 @@ export const allLuaScripts: LuaScript[] = [ addCanceledOrderIdScript, addStatefulOrderUpdateScript, removeStatefulOrderUpdateScript, - addMarketPriceScript, - getMarketMedianScript, ]; diff --git a/indexer/packages/redis/src/index.ts b/indexer/packages/redis/src/index.ts index 5c7aeed103..2ce64e9b88 100644 --- a/indexer/packages/redis/src/index.ts +++ b/indexer/packages/redis/src/index.ts @@ -12,7 +12,6 @@ export * as CanceledOrdersCache from './caches/canceled-orders-cache'; export * as StatefulOrderUpdatesCache from './caches/stateful-order-updates-cache'; export * as StateFilledQuantumsCache from './caches/state-filled-quantums-cache'; export * as LeaderboardPnlProcessedCache from './caches/leaderboard-processed-cache'; -export * as OrderbookMidPricesCache from './caches/orderbook-mid-prices-cache'; export { placeOrder } from './caches/place-order'; export { removeOrder } from './caches/remove-order'; export { updateOrder } from './caches/update-order'; diff --git a/indexer/packages/redis/src/scripts/add_market_price.lua b/indexer/packages/redis/src/scripts/add_market_price.lua deleted file mode 100644 index 0e1467bb31..0000000000 --- a/indexer/packages/redis/src/scripts/add_market_price.lua +++ /dev/null @@ -1,17 +0,0 @@ --- Key for the ZSET storing price data -local priceCacheKey = KEYS[1] --- Price to be added -local price = tonumber(ARGV[1]) --- Current timestamp -local nowSeconds = tonumber(ARGV[2]) --- Time window (5 seconds) -local fiveSeconds = 5 - --- 1. Add the price to the sorted set (score is the current timestamp) -redis.call("zadd", priceCacheKey, nowSeconds, price) - --- 2. Remove any entries older than 5 seconds -local cutoffTime = nowSeconds - fiveSeconds -redis.call("zremrangebyscore", priceCacheKey, "-inf", cutoffTime) - -return true \ No newline at end of file diff --git a/indexer/packages/redis/src/scripts/get_market_median_price.lua b/indexer/packages/redis/src/scripts/get_market_median_price.lua deleted file mode 100644 index 281da9bed8..0000000000 --- a/indexer/packages/redis/src/scripts/get_market_median_price.lua +++ /dev/null @@ -1,23 +0,0 @@ --- Key for the sorted set storing price data -local priceCacheKey = KEYS[1] - --- Get all the prices from the sorted set (ascending order) -local prices = redis.call('zrange', priceCacheKey, 0, -1) - --- If no prices are found, return nil -if #prices == 0 then - return nil -end - --- Calculate the middle index -local middle = math.floor(#prices / 2) - --- Calculate median -if #prices % 2 == 0 then - -- If even, return the average of the two middle elements - local median = (tonumber(prices[middle]) + tonumber(prices[middle + 1])) / 2 - return tostring(median) -else - -- If odd, return the middle element - return prices[middle + 1] -end diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index d58ebd0d2a..d1c257b80b 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -18,6 +18,7 @@ import { testMocks, Transaction, helpers, + OrderSide, } from '@dydxprotocol-indexer/postgres'; import { CandleMessage, CandleMessage_Resolution } from '@dydxprotocol-indexer/v4-protos'; import Big from 'big.js'; @@ -31,11 +32,9 @@ import { KafkaPublisher } from '../../src/lib/kafka-publisher'; import { ConsolidatedKafkaEvent } from '../../src/lib/types'; import { defaultTradeContent, defaultTradeKafkaEvent } from '../helpers/constants'; import { contentToSingleTradeMessage, createConsolidatedKafkaEventFromTrade } from '../helpers/kafka-publisher-helpers'; +import { updatePriceLevel } from '../helpers/redis-helpers'; import { redisClient } from '../../src/helpers/redis/redis-controller'; -import { - redis, - OrderbookMidPricesCache, -} from '@dydxprotocol-indexer/redis'; +import { redis } from '@dydxprotocol-indexer/redis'; describe('candleHelper', () => { beforeAll(async () => { @@ -114,12 +113,9 @@ describe('candleHelper', () => { defaultTradeKafkaEvent2, ]); - const ticker = 'BTC-USD'; - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, ticker, '100000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '105000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '110000'), - ]); + // Create Orderbook levels to set orderbookMidPrice open & close + await updatePriceLevel('BTC-USD', '100000', OrderSide.BUY); + await updatePriceLevel('BTC-USD', '110000', OrderSide.SELL); await runUpdateCandles(publisher); @@ -159,12 +155,8 @@ describe('candleHelper', () => { defaultTradeKafkaEvent2, ]); - const ticker = 'BTC-USD'; - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, ticker, '80000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '81000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '80500'), - ]); + await updatePriceLevel('BTC-USD', '80000', OrderSide.BUY); + await updatePriceLevel('BTC-USD', '81000', OrderSide.SELL); // Create Perpetual Position to set open position const openInterest: string = '100'; @@ -435,7 +427,9 @@ describe('candleHelper', () => { containsKafkaMessages: boolean = true, orderbookMidPrice: number, ) => { - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', orderbookMidPrice.toFixed()); + const midPriceSpread = 10; + await updatePriceLevel('BTC-USD', String(orderbookMidPrice + midPriceSpread), OrderSide.SELL); + await updatePriceLevel('BTC-USD', String(orderbookMidPrice - midPriceSpread), OrderSide.BUY); if (initialCandle !== undefined) { await CandleTable.create(initialCandle); @@ -500,7 +494,9 @@ describe('candleHelper', () => { ); await startCandleCache(); - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + // Update Orderbook levels + await updatePriceLevel('BTC-USD', '10010', OrderSide.SELL); + await updatePriceLevel('BTC-USD', '10000', OrderSide.BUY); const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([ @@ -598,7 +594,9 @@ describe('candleHelper', () => { ); await startCandleCache(); - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + // Update Orderbook levels + await updatePriceLevel('BTC-USD', '10010', OrderSide.SELL); + await updatePriceLevel('BTC-USD', '10000', OrderSide.BUY); const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([]); @@ -662,19 +660,22 @@ describe('candleHelper', () => { }); it('successfully creates an orderbook price map for each market', async () => { - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), - OrderbookMidPricesCache.setPrice(redisClient, 'ISO-USD', '115000'), - OrderbookMidPricesCache.setPrice(redisClient, 'ETH-USD', '150000'), - ]); + await updatePriceLevel('BTC-USD', '100000', OrderSide.BUY); + await updatePriceLevel('BTC-USD', '110000', OrderSide.SELL); + + await updatePriceLevel('ISO-USD', '110000', OrderSide.BUY); + await updatePriceLevel('ISO-USD', '120000', OrderSide.SELL); + + await updatePriceLevel('ETH-USD', '100000', OrderSide.BUY); + await updatePriceLevel('ETH-USD', '200000', OrderSide.SELL); const map = await getOrderbookMidPriceMap(); expect(map).toEqual({ 'BTC-USD': '105000', 'ETH-USD': '150000', 'ISO-USD': '115000', - 'ISO2-USD': null, - 'SHIB-USD': null, + 'ISO2-USD': undefined, + 'SHIB-USD': undefined, }); }); }); diff --git a/indexer/services/ender/src/lib/candles-generator.ts b/indexer/services/ender/src/lib/candles-generator.ts index b232a66eb0..d7dd7bba34 100644 --- a/indexer/services/ender/src/lib/candles-generator.ts +++ b/indexer/services/ender/src/lib/candles-generator.ts @@ -20,7 +20,7 @@ import { TradeMessageContents, helpers, } from '@dydxprotocol-indexer/postgres'; -import { OrderbookMidPricesCache } from '@dydxprotocol-indexer/redis'; +import { OrderbookLevelsCache } from '@dydxprotocol-indexer/redis'; import { CandleMessage } from '@dydxprotocol-indexer/v4-protos'; import Big from 'big.js'; import _ from 'lodash'; @@ -538,9 +538,9 @@ export async function getOrderbookMidPriceMap(): Promise<{ [ticker: string]: Ord const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()); const promises = perpetualMarkets.map(async (perpetualMarket: PerpetualMarketFromDatabase) => { - const price = await OrderbookMidPricesCache.getMedianPrice( - redisClient, + const price = await OrderbookLevelsCache.getOrderBookMidPrice( perpetualMarket.ticker, + redisClient, ); return { [perpetualMarket.ticker]: price === undefined ? undefined : price }; }); diff --git a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts deleted file mode 100644 index cd0eee3970..0000000000 --- a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { - dbHelpers, - testConstants, - testMocks, -} from '@dydxprotocol-indexer/postgres'; -import { - OrderbookMidPricesCache, - OrderbookLevelsCache, - redis, -} from '@dydxprotocol-indexer/redis'; -import { redisClient } from '../../src/helpers/redis'; -import runTask from '../../src/tasks/cache-orderbook-mid-prices'; - -jest.mock('@dydxprotocol-indexer/base', () => ({ - ...jest.requireActual('@dydxprotocol-indexer/base'), - logger: { - info: jest.fn(), - error: jest.fn(), - }, -})); - -jest.mock('@dydxprotocol-indexer/redis', () => ({ - ...jest.requireActual('@dydxprotocol-indexer/redis'), - OrderbookLevelsCache: { - getOrderBookMidPrice: jest.fn(), - }, -})); - -describe('cache-orderbook-mid-prices', () => { - beforeAll(async () => { - await dbHelpers.migrate(); - }); - - beforeEach(async () => { - await dbHelpers.clearData(); - await redis.deleteAllAsync(redisClient); - await testMocks.seedData(); - }); - - afterAll(async () => { - await dbHelpers.teardown(); - jest.resetAllMocks(); - }); - - it('caches mid prices for all markets', async () => { - const market1 = testConstants.defaultPerpetualMarket; - const market2 = testConstants.defaultPerpetualMarket2; - - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockResolvedValueOnce('100.5'); // For market1 - mockGetOrderBookMidPrice.mockResolvedValueOnce('200.75'); // For market2 - - await runTask(); - - // Check if the mock was called with the correct arguments - expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market1.ticker, redisClient); - expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market2.ticker, redisClient); - - // Check if prices were cached correctly - const price1 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market1.ticker); - const price2 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market2.ticker); - - expect(price1).toBe('100.5'); - expect(price2).toBe('200.75'); - }); - - it('handles undefined prices', async () => { - const market = testConstants.defaultPerpetualMarket; - - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockResolvedValueOnce(undefined); - - await runTask(); - - const price = await OrderbookMidPricesCache.getMedianPrice(redisClient, market.ticker); - expect(price).toBeNull(); - - // Check that a log message was created - expect(jest.requireMock('@dydxprotocol-indexer/base').logger.info).toHaveBeenCalledWith({ - at: 'cache-orderbook-mid-prices#runTask', - message: `undefined price for ${market.ticker}`, - }); - }); - - it('handles errors', async () => { - // Mock OrderbookLevelsCache.getOrderBookMidPrice to throw an error - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockRejectedValueOnce(new Error('Test error')); - - await runTask(); - - expect(jest.requireMock('@dydxprotocol-indexer/base').logger.error).toHaveBeenCalledWith({ - at: 'cache-orderbook-mid-prices#runTask', - message: 'Test error', - error: expect.any(Error), - }); - }); -}); diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 9f0f00c487..a8ec2cb87b 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -60,7 +60,6 @@ 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_CACHE_ORDERBOOK_MID_PRICES: parseBoolean({ default: true }), // Loop Timing LOOPS_INTERVAL_MS_MARKET_UPDATER: parseInteger({ @@ -138,9 +137,6 @@ export const configSchema = { LOOPS_INTERVAL_MS_DELETE_FIREBASE_NOTIFICATION_TOKENS_MONTHLY: parseInteger({ default: 30 * ONE_DAY_IN_MILLISECONDS, }), - LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES: parseInteger({ - default: ONE_SECOND_IN_MILLISECONDS, - }), // Start delay START_DELAY_ENABLED: parseBoolean({ default: true }), diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index bfdee334c7..f52903ac19 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -10,7 +10,6 @@ import { connect as connectToRedis, } from './helpers/redis'; import aggregateTradingRewardsTasks from './tasks/aggregate-trading-rewards'; -import cacheOrderbookMidPrices from './tasks/cache-orderbook-mid-prices'; import cancelStaleOrdersTask from './tasks/cancel-stale-orders'; import createLeaderboardTask from './tasks/create-leaderboard'; import createPnlTicksTask from './tasks/create-pnl-ticks'; @@ -273,14 +272,6 @@ async function start(): Promise { ); } - if (config.LOOPS_ENABLED_CACHE_ORDERBOOK_MID_PRICES) { - startLoop( - cacheOrderbookMidPrices, - 'cache_orderbook_mid_prices', - config.LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES, - ); - } - logger.info({ at: 'index', message: 'Successfully started', diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts deleted file mode 100644 index 644f50df6f..0000000000 --- a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - logger, -} from '@dydxprotocol-indexer/base'; -import { - PerpetualMarketFromDatabase, - PerpetualMarketTable, -} from '@dydxprotocol-indexer/postgres'; -import { - OrderbookMidPricesCache, - OrderbookLevelsCache, -} from '@dydxprotocol-indexer/redis'; - -import { redisClient } from '../helpers/redis'; - -/** - * Updates OrderbookMidPricesCache with current orderbook mid price for each market - */ -export default async function runTask(): Promise { - const markets: PerpetualMarketFromDatabase[] = await PerpetualMarketTable.findAll({}, []); - - for (const market of markets) { - try { - const price = await OrderbookLevelsCache.getOrderBookMidPrice(market.ticker, redisClient); - if (price) { - await OrderbookMidPricesCache.setPrice(redisClient, market.ticker, price); - } else { - logger.info({ - at: 'cache-orderbook-mid-prices#runTask', - message: `undefined price for ${market.ticker}`, - }); - } - } catch (error) { - logger.error({ - at: 'cache-orderbook-mid-prices#runTask', - message: error.message, - error, - }); - } - } -} From ce8f48415259afa50e3e6ba4a4ef8679aa31510e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:05:53 -0400 Subject: [PATCH 002/120] Add Orderbook Mid Price Cache (backport #2338) (#2340) Co-authored-by: Adam Fraser --- .../caches/orderbook-mid-prices-cache.test.ts | 136 ++++++++++++++++++ .../src/caches/orderbook-mid-prices-cache.ts | 127 ++++++++++++++++ indexer/packages/redis/src/caches/scripts.ts | 4 + indexer/packages/redis/src/index.ts | 1 + .../redis/src/scripts/add_market_price.lua | 17 +++ .../src/scripts/get_market_median_price.lua | 22 +++ .../__tests__/lib/candles-generator.test.ts | 53 ++++--- .../ender/src/lib/candles-generator.ts | 6 +- .../tasks/cache-orderbook-mid-prices.test.ts | 98 +++++++++++++ indexer/services/roundtable/src/config.ts | 4 + indexer/services/roundtable/src/index.ts | 9 ++ .../src/tasks/cache-orderbook-mid-prices.ts | 40 ++++++ 12 files changed, 487 insertions(+), 30 deletions(-) create mode 100644 indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts create mode 100644 indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts create mode 100644 indexer/packages/redis/src/scripts/add_market_price.lua create mode 100644 indexer/packages/redis/src/scripts/get_market_median_price.lua create mode 100644 indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts create mode 100644 indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts diff --git a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts new file mode 100644 index 0000000000..5dfd662f68 --- /dev/null +++ b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts @@ -0,0 +1,136 @@ +import { deleteAllAsync } from '../../src/helpers/redis'; +import { redis as client } from '../helpers/utils'; +import { + setPrice, + getMedianPrice, + ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX, +} from '../../src/caches/orderbook-mid-prices-cache'; + +describe('orderbook-mid-prices-cache', () => { + const ticker: string = 'BTC-USD'; + + beforeEach(async () => { + await deleteAllAsync(client); + }); + + describe('setPrice', () => { + it('sets a price for a ticker', async () => { + await setPrice(client, ticker, '50000'); + + await client.zrange( + `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, + 0, + -1, + (_: any, response: string[]) => { + expect(response[0]).toBe('50000'); + }, + ); + }); + + it('sets multiple prices for a ticker', async () => { + await Promise.all([ + setPrice(client, ticker, '50000'), + setPrice(client, ticker, '51000'), + setPrice(client, ticker, '49000'), + ]); + + await client.zrange( + `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, + 0, + -1, + (_: any, response: string[]) => { + expect(response).toEqual(['49000', '50000', '51000']); + }, + ); + }); + }); + + describe('getMedianPrice', () => { + it('returns null when no prices are set', async () => { + const result = await getMedianPrice(client, ticker); + expect(result).toBeNull(); + }); + + it('returns the median price for odd number of prices', async () => { + await Promise.all([ + setPrice(client, ticker, '50000'), + setPrice(client, ticker, '51000'), + setPrice(client, ticker, '49000'), + ]); + + const result = await getMedianPrice(client, ticker); + expect(result).toBe('50000'); + }); + + it('returns the median price for even number of prices', async () => { + await Promise.all([ + setPrice(client, ticker, '50000'), + setPrice(client, ticker, '51000'), + setPrice(client, ticker, '49000'), + setPrice(client, ticker, '52000'), + ]); + + const result = await getMedianPrice(client, ticker); + expect(result).toBe('50500'); + }); + + it('returns the correct median price after 5 seconds', async () => { + jest.useFakeTimers(); + + const nowSeconds = Math.floor(Date.now() / 1000); + jest.setSystemTime(nowSeconds * 1000); + + await Promise.all([ + setPrice(client, ticker, '50000'), + setPrice(client, ticker, '51000'), + ]); + + jest.advanceTimersByTime(6000); // Advance time by 6 seconds + await Promise.all([ + setPrice(client, ticker, '49000'), + setPrice(client, ticker, '48000'), + setPrice(client, ticker, '52000'), + setPrice(client, ticker, '53000'), + ]); + + const result = await getMedianPrice(client, ticker); + expect(result).toBe('50500'); + + jest.useRealTimers(); + }); + + it('returns the correct median price for small numbers with even number of prices', async () => { + await Promise.all([ + setPrice(client, ticker, '0.00000000002345'), + setPrice(client, ticker, '0.00000000002346'), + ]); + + const midPrice1 = await getMedianPrice(client, ticker); + expect(midPrice1).toEqual('0.000000000023455'); + }); + + it('returns the correct median price for small numbers with odd number of prices', async () => { + await Promise.all([ + setPrice(client, ticker, '0.00000000001'), + setPrice(client, ticker, '0.00000000002'), + setPrice(client, ticker, '0.00000000003'), + setPrice(client, ticker, '0.00000000004'), + setPrice(client, ticker, '0.00000000005'), + ]); + + const midPrice1 = await getMedianPrice(client, ticker); + expect(midPrice1).toEqual('0.00000000003'); + + await deleteAllAsync(client); + + await Promise.all([ + setPrice(client, ticker, '0.00000847007'), + setPrice(client, ticker, '0.00000847006'), + setPrice(client, ticker, '0.00000847008'), + ]); + + const midPrice2 = await getMedianPrice(client, ticker); + expect(midPrice2).toEqual('0.00000847007'); + }); + }); +}); diff --git a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts new file mode 100644 index 0000000000..ece95a3ca2 --- /dev/null +++ b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts @@ -0,0 +1,127 @@ +import Big from 'big.js'; +import { Callback, RedisClient } from 'redis'; + +import { + addMarketPriceScript, + getMarketMedianScript, +} from './scripts'; + +// Cache of orderbook prices for each clob pair +// Each price is cached for a 5 second window and in a ZSET +export const ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX: string = 'v4/orderbook_mid_prices/'; + +/** + * Generates a cache key for a given ticker's orderbook mid price. + * @param ticker The ticker symbol + * @returns The cache key string + */ +function getOrderbookMidPriceCacheKey(ticker: string): string { + return `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`; +} + +/** + * Adds a price to the market prices cache for a given ticker. + * Uses a Lua script to add the price with a timestamp to a sorted set in Redis. + * @param client The Redis client + * @param ticker The ticker symbol + * @param price The price to be added + * @returns A promise that resolves when the operation is complete + */ +export async function setPrice( + client: RedisClient, + ticker: string, + price: string, +): Promise { + // Number of keys for the lua script. + const numKeys: number = 1; + + let evalAsync: ( + marketCacheKey: string, + ) => Promise = (marketCacheKey) => { + + return new Promise((resolve, reject) => { + const callback: Callback = ( + err: Error | null, + ) => { + if (err) { + return reject(err); + } + return resolve(); + }; + + const nowSeconds = Math.floor(Date.now() / 1000); // Current time in seconds + client.evalsha( + addMarketPriceScript.hash, + numKeys, + marketCacheKey, + price, + nowSeconds, + callback, + ); + + }); + }; + evalAsync = evalAsync.bind(client); + + return evalAsync( + getOrderbookMidPriceCacheKey(ticker), + ); +} + +/** + * Retrieves the median price for a given ticker from the cache. + * Uses a Lua script to fetch either the middle element (for odd number of prices) + * or the two middle elements (for even number of prices) from a sorted set in Redis. + * If two middle elements are returned, their average is calculated in JavaScript. + * @param client The Redis client + * @param ticker The ticker symbol + * @returns A promise that resolves with the median price as a string, or null if not found + */ +export async function getMedianPrice(client: RedisClient, ticker: string): Promise { + let evalAsync: ( + marketCacheKey: string, + ) => Promise = ( + marketCacheKey, + ) => { + return new Promise((resolve, reject) => { + const callback: Callback = ( + err: Error | null, + results: string[], + ) => { + if (err) { + return reject(err); + } + return resolve(results); + }; + + client.evalsha( + getMarketMedianScript.hash, + 1, + marketCacheKey, + callback, + ); + }); + }; + evalAsync = evalAsync.bind(client); + + const prices = await evalAsync( + getOrderbookMidPriceCacheKey(ticker), + ); + + if (!prices || prices.length === 0) { + return null; + } + + if (prices.length === 1) { + return Big(prices[0]).toFixed(); + } + + if (prices.length === 2) { + const [price1, price2] = prices.map((price) => { + return Big(price); + }); + return price1.plus(price2).div(2).toFixed(); + } + + return null; +} diff --git a/indexer/packages/redis/src/caches/scripts.ts b/indexer/packages/redis/src/caches/scripts.ts index 3e1032c6f2..f4f74bffd5 100644 --- a/indexer/packages/redis/src/caches/scripts.ts +++ b/indexer/packages/redis/src/caches/scripts.ts @@ -63,6 +63,8 @@ export const removeOrderScript: LuaScript = newLuaScript('removeOrder', '../scri export const addCanceledOrderIdScript: LuaScript = newLuaScript('addCanceledOrderId', '../scripts/add_canceled_order_id.lua'); export const addStatefulOrderUpdateScript: LuaScript = newLuaScript('addStatefulOrderUpdate', '../scripts/add_stateful_order_update.lua'); export const removeStatefulOrderUpdateScript: LuaScript = newLuaScript('removeStatefulOrderUpdate', '../scripts/remove_stateful_order_update.lua'); +export const addMarketPriceScript: LuaScript = newLuaScript('addMarketPrice', '../scripts/add_market_price.lua'); +export const getMarketMedianScript: LuaScript = newLuaScript('getMarketMedianPrice', '../scripts/get_market_median_price.lua'); export const allLuaScripts: LuaScript[] = [ deleteZeroPriceLevelScript, @@ -75,4 +77,6 @@ export const allLuaScripts: LuaScript[] = [ addCanceledOrderIdScript, addStatefulOrderUpdateScript, removeStatefulOrderUpdateScript, + addMarketPriceScript, + getMarketMedianScript, ]; diff --git a/indexer/packages/redis/src/index.ts b/indexer/packages/redis/src/index.ts index 2ce64e9b88..5c7aeed103 100644 --- a/indexer/packages/redis/src/index.ts +++ b/indexer/packages/redis/src/index.ts @@ -12,6 +12,7 @@ export * as CanceledOrdersCache from './caches/canceled-orders-cache'; export * as StatefulOrderUpdatesCache from './caches/stateful-order-updates-cache'; export * as StateFilledQuantumsCache from './caches/state-filled-quantums-cache'; export * as LeaderboardPnlProcessedCache from './caches/leaderboard-processed-cache'; +export * as OrderbookMidPricesCache from './caches/orderbook-mid-prices-cache'; export { placeOrder } from './caches/place-order'; export { removeOrder } from './caches/remove-order'; export { updateOrder } from './caches/update-order'; diff --git a/indexer/packages/redis/src/scripts/add_market_price.lua b/indexer/packages/redis/src/scripts/add_market_price.lua new file mode 100644 index 0000000000..0e1467bb31 --- /dev/null +++ b/indexer/packages/redis/src/scripts/add_market_price.lua @@ -0,0 +1,17 @@ +-- Key for the ZSET storing price data +local priceCacheKey = KEYS[1] +-- Price to be added +local price = tonumber(ARGV[1]) +-- Current timestamp +local nowSeconds = tonumber(ARGV[2]) +-- Time window (5 seconds) +local fiveSeconds = 5 + +-- 1. Add the price to the sorted set (score is the current timestamp) +redis.call("zadd", priceCacheKey, nowSeconds, price) + +-- 2. Remove any entries older than 5 seconds +local cutoffTime = nowSeconds - fiveSeconds +redis.call("zremrangebyscore", priceCacheKey, "-inf", cutoffTime) + +return true \ No newline at end of file diff --git a/indexer/packages/redis/src/scripts/get_market_median_price.lua b/indexer/packages/redis/src/scripts/get_market_median_price.lua new file mode 100644 index 0000000000..a318296f20 --- /dev/null +++ b/indexer/packages/redis/src/scripts/get_market_median_price.lua @@ -0,0 +1,22 @@ +-- Key for the sorted set storing price data +local priceCacheKey = KEYS[1] + +-- Get all the prices from the sorted set (ascending order) +local prices = redis.call('zrange', priceCacheKey, 0, -1) + +-- If no prices are found, return nil +if #prices == 0 then + return nil +end + +-- Calculate the middle index +local middle = math.floor(#prices / 2) + +-- Calculate median +if #prices % 2 == 0 then + -- If even, return both prices, division will be handled in Javascript + return {prices[middle], prices[middle + 1]} +else + -- If odd, return the middle element + return {prices[middle + 1]} +end diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index d1c257b80b..d58ebd0d2a 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -18,7 +18,6 @@ import { testMocks, Transaction, helpers, - OrderSide, } from '@dydxprotocol-indexer/postgres'; import { CandleMessage, CandleMessage_Resolution } from '@dydxprotocol-indexer/v4-protos'; import Big from 'big.js'; @@ -32,9 +31,11 @@ import { KafkaPublisher } from '../../src/lib/kafka-publisher'; import { ConsolidatedKafkaEvent } from '../../src/lib/types'; import { defaultTradeContent, defaultTradeKafkaEvent } from '../helpers/constants'; import { contentToSingleTradeMessage, createConsolidatedKafkaEventFromTrade } from '../helpers/kafka-publisher-helpers'; -import { updatePriceLevel } from '../helpers/redis-helpers'; import { redisClient } from '../../src/helpers/redis/redis-controller'; -import { redis } from '@dydxprotocol-indexer/redis'; +import { + redis, + OrderbookMidPricesCache, +} from '@dydxprotocol-indexer/redis'; describe('candleHelper', () => { beforeAll(async () => { @@ -113,9 +114,12 @@ describe('candleHelper', () => { defaultTradeKafkaEvent2, ]); - // Create Orderbook levels to set orderbookMidPrice open & close - await updatePriceLevel('BTC-USD', '100000', OrderSide.BUY); - await updatePriceLevel('BTC-USD', '110000', OrderSide.SELL); + const ticker = 'BTC-USD'; + await Promise.all([ + OrderbookMidPricesCache.setPrice(redisClient, ticker, '100000'), + OrderbookMidPricesCache.setPrice(redisClient, ticker, '105000'), + OrderbookMidPricesCache.setPrice(redisClient, ticker, '110000'), + ]); await runUpdateCandles(publisher); @@ -155,8 +159,12 @@ describe('candleHelper', () => { defaultTradeKafkaEvent2, ]); - await updatePriceLevel('BTC-USD', '80000', OrderSide.BUY); - await updatePriceLevel('BTC-USD', '81000', OrderSide.SELL); + const ticker = 'BTC-USD'; + await Promise.all([ + OrderbookMidPricesCache.setPrice(redisClient, ticker, '80000'), + OrderbookMidPricesCache.setPrice(redisClient, ticker, '81000'), + OrderbookMidPricesCache.setPrice(redisClient, ticker, '80500'), + ]); // Create Perpetual Position to set open position const openInterest: string = '100'; @@ -427,9 +435,7 @@ describe('candleHelper', () => { containsKafkaMessages: boolean = true, orderbookMidPrice: number, ) => { - const midPriceSpread = 10; - await updatePriceLevel('BTC-USD', String(orderbookMidPrice + midPriceSpread), OrderSide.SELL); - await updatePriceLevel('BTC-USD', String(orderbookMidPrice - midPriceSpread), OrderSide.BUY); + await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', orderbookMidPrice.toFixed()); if (initialCandle !== undefined) { await CandleTable.create(initialCandle); @@ -494,9 +500,7 @@ describe('candleHelper', () => { ); await startCandleCache(); - // Update Orderbook levels - await updatePriceLevel('BTC-USD', '10010', OrderSide.SELL); - await updatePriceLevel('BTC-USD', '10000', OrderSide.BUY); + await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([ @@ -594,9 +598,7 @@ describe('candleHelper', () => { ); await startCandleCache(); - // Update Orderbook levels - await updatePriceLevel('BTC-USD', '10010', OrderSide.SELL); - await updatePriceLevel('BTC-USD', '10000', OrderSide.BUY); + await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([]); @@ -660,22 +662,19 @@ describe('candleHelper', () => { }); it('successfully creates an orderbook price map for each market', async () => { - await updatePriceLevel('BTC-USD', '100000', OrderSide.BUY); - await updatePriceLevel('BTC-USD', '110000', OrderSide.SELL); - - await updatePriceLevel('ISO-USD', '110000', OrderSide.BUY); - await updatePriceLevel('ISO-USD', '120000', OrderSide.SELL); - - await updatePriceLevel('ETH-USD', '100000', OrderSide.BUY); - await updatePriceLevel('ETH-USD', '200000', OrderSide.SELL); + await Promise.all([ + OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), + OrderbookMidPricesCache.setPrice(redisClient, 'ISO-USD', '115000'), + OrderbookMidPricesCache.setPrice(redisClient, 'ETH-USD', '150000'), + ]); const map = await getOrderbookMidPriceMap(); expect(map).toEqual({ 'BTC-USD': '105000', 'ETH-USD': '150000', 'ISO-USD': '115000', - 'ISO2-USD': undefined, - 'SHIB-USD': undefined, + 'ISO2-USD': null, + 'SHIB-USD': null, }); }); }); diff --git a/indexer/services/ender/src/lib/candles-generator.ts b/indexer/services/ender/src/lib/candles-generator.ts index d7dd7bba34..b232a66eb0 100644 --- a/indexer/services/ender/src/lib/candles-generator.ts +++ b/indexer/services/ender/src/lib/candles-generator.ts @@ -20,7 +20,7 @@ import { TradeMessageContents, helpers, } from '@dydxprotocol-indexer/postgres'; -import { OrderbookLevelsCache } from '@dydxprotocol-indexer/redis'; +import { OrderbookMidPricesCache } from '@dydxprotocol-indexer/redis'; import { CandleMessage } from '@dydxprotocol-indexer/v4-protos'; import Big from 'big.js'; import _ from 'lodash'; @@ -538,9 +538,9 @@ export async function getOrderbookMidPriceMap(): Promise<{ [ticker: string]: Ord const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()); const promises = perpetualMarkets.map(async (perpetualMarket: PerpetualMarketFromDatabase) => { - const price = await OrderbookLevelsCache.getOrderBookMidPrice( - perpetualMarket.ticker, + const price = await OrderbookMidPricesCache.getMedianPrice( redisClient, + perpetualMarket.ticker, ); return { [perpetualMarket.ticker]: price === undefined ? undefined : price }; }); diff --git a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts new file mode 100644 index 0000000000..cd0eee3970 --- /dev/null +++ b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts @@ -0,0 +1,98 @@ +import { + dbHelpers, + testConstants, + testMocks, +} from '@dydxprotocol-indexer/postgres'; +import { + OrderbookMidPricesCache, + OrderbookLevelsCache, + redis, +} from '@dydxprotocol-indexer/redis'; +import { redisClient } from '../../src/helpers/redis'; +import runTask from '../../src/tasks/cache-orderbook-mid-prices'; + +jest.mock('@dydxprotocol-indexer/base', () => ({ + ...jest.requireActual('@dydxprotocol-indexer/base'), + logger: { + info: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@dydxprotocol-indexer/redis', () => ({ + ...jest.requireActual('@dydxprotocol-indexer/redis'), + OrderbookLevelsCache: { + getOrderBookMidPrice: jest.fn(), + }, +})); + +describe('cache-orderbook-mid-prices', () => { + beforeAll(async () => { + await dbHelpers.migrate(); + }); + + beforeEach(async () => { + await dbHelpers.clearData(); + await redis.deleteAllAsync(redisClient); + await testMocks.seedData(); + }); + + afterAll(async () => { + await dbHelpers.teardown(); + jest.resetAllMocks(); + }); + + it('caches mid prices for all markets', async () => { + const market1 = testConstants.defaultPerpetualMarket; + const market2 = testConstants.defaultPerpetualMarket2; + + const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); + mockGetOrderBookMidPrice.mockResolvedValueOnce('100.5'); // For market1 + mockGetOrderBookMidPrice.mockResolvedValueOnce('200.75'); // For market2 + + await runTask(); + + // Check if the mock was called with the correct arguments + expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market1.ticker, redisClient); + expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market2.ticker, redisClient); + + // Check if prices were cached correctly + const price1 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market1.ticker); + const price2 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market2.ticker); + + expect(price1).toBe('100.5'); + expect(price2).toBe('200.75'); + }); + + it('handles undefined prices', async () => { + const market = testConstants.defaultPerpetualMarket; + + const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); + mockGetOrderBookMidPrice.mockResolvedValueOnce(undefined); + + await runTask(); + + const price = await OrderbookMidPricesCache.getMedianPrice(redisClient, market.ticker); + expect(price).toBeNull(); + + // Check that a log message was created + expect(jest.requireMock('@dydxprotocol-indexer/base').logger.info).toHaveBeenCalledWith({ + at: 'cache-orderbook-mid-prices#runTask', + message: `undefined price for ${market.ticker}`, + }); + }); + + it('handles errors', async () => { + // Mock OrderbookLevelsCache.getOrderBookMidPrice to throw an error + const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); + mockGetOrderBookMidPrice.mockRejectedValueOnce(new Error('Test error')); + + await runTask(); + + expect(jest.requireMock('@dydxprotocol-indexer/base').logger.error).toHaveBeenCalledWith({ + at: 'cache-orderbook-mid-prices#runTask', + message: 'Test error', + error: expect.any(Error), + }); + }); +}); diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index a8ec2cb87b..9f0f00c487 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_CACHE_ORDERBOOK_MID_PRICES: parseBoolean({ default: true }), // Loop Timing LOOPS_INTERVAL_MS_MARKET_UPDATER: parseInteger({ @@ -137,6 +138,9 @@ export const configSchema = { LOOPS_INTERVAL_MS_DELETE_FIREBASE_NOTIFICATION_TOKENS_MONTHLY: parseInteger({ default: 30 * ONE_DAY_IN_MILLISECONDS, }), + LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES: parseInteger({ + default: ONE_SECOND_IN_MILLISECONDS, + }), // Start delay START_DELAY_ENABLED: parseBoolean({ default: true }), diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index f52903ac19..bfdee334c7 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -10,6 +10,7 @@ import { connect as connectToRedis, } from './helpers/redis'; import aggregateTradingRewardsTasks from './tasks/aggregate-trading-rewards'; +import cacheOrderbookMidPrices from './tasks/cache-orderbook-mid-prices'; import cancelStaleOrdersTask from './tasks/cancel-stale-orders'; import createLeaderboardTask from './tasks/create-leaderboard'; import createPnlTicksTask from './tasks/create-pnl-ticks'; @@ -272,6 +273,14 @@ async function start(): Promise { ); } + if (config.LOOPS_ENABLED_CACHE_ORDERBOOK_MID_PRICES) { + startLoop( + cacheOrderbookMidPrices, + 'cache_orderbook_mid_prices', + config.LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES, + ); + } + logger.info({ at: 'index', message: 'Successfully started', diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts new file mode 100644 index 0000000000..644f50df6f --- /dev/null +++ b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts @@ -0,0 +1,40 @@ +import { + logger, +} from '@dydxprotocol-indexer/base'; +import { + PerpetualMarketFromDatabase, + PerpetualMarketTable, +} from '@dydxprotocol-indexer/postgres'; +import { + OrderbookMidPricesCache, + OrderbookLevelsCache, +} from '@dydxprotocol-indexer/redis'; + +import { redisClient } from '../helpers/redis'; + +/** + * Updates OrderbookMidPricesCache with current orderbook mid price for each market + */ +export default async function runTask(): Promise { + const markets: PerpetualMarketFromDatabase[] = await PerpetualMarketTable.findAll({}, []); + + for (const market of markets) { + try { + const price = await OrderbookLevelsCache.getOrderBookMidPrice(market.ticker, redisClient); + if (price) { + await OrderbookMidPricesCache.setPrice(redisClient, market.ticker, price); + } else { + logger.info({ + at: 'cache-orderbook-mid-prices#runTask', + message: `undefined price for ${market.ticker}`, + }); + } + } catch (error) { + logger.error({ + at: 'cache-orderbook-mid-prices#runTask', + message: error.message, + error, + }); + } + } +} From 8a0a7484bb6613a8b7a4b0337fa1aae9db74812a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:38:32 -0400 Subject: [PATCH 003/120] [OTE-784] Limit addresses for compliance check to dydx wallets with deposit (backport #2330) (#2353) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- .../src/clients/elliptic-provider.ts | 4 +- indexer/packages/compliance/src/index.ts | 1 + .../stores/compliance-data-table.test.ts | 25 ++++++++ .../postgres/src/stores/compliance-table.ts | 11 ++++ .../postgres/src/types/query-types.ts | 2 + .../api/v4/compliance-controller.test.ts | 34 ++++++++++- .../api/v4/compliance-controller.ts | 17 +++++- .../tasks/update-compliance-data.test.ts | 60 +++++++++++++++++++ .../src/tasks/update-compliance-data.ts | 28 ++++++++- 9 files changed, 178 insertions(+), 4 deletions(-) diff --git a/indexer/packages/compliance/src/clients/elliptic-provider.ts b/indexer/packages/compliance/src/clients/elliptic-provider.ts index 74df5c538d..9004470047 100644 --- a/indexer/packages/compliance/src/clients/elliptic-provider.ts +++ b/indexer/packages/compliance/src/clients/elliptic-provider.ts @@ -26,6 +26,8 @@ export const API_PATH: string = '/v2/wallet/synchronous'; export const API_URI: string = `https://aml-api.elliptic.co${API_PATH}`; export const RISK_SCORE_KEY: string = 'risk_score'; export const NO_RULES_TRIGGERED_RISK_SCORE: number = -1; +// We use different negative values of risk score to represent different elliptic response states +export const NOT_IN_BLOCKCHAIN_RISK_SCORE: number = -2; export class EllipticProviderClient extends ComplianceClient { private apiKey: string; @@ -98,7 +100,7 @@ export class EllipticProviderClient extends ComplianceClient { `${config.SERVICE_NAME}.get_elliptic_risk_score.status_code`, { status: '404' }, ); - return NO_RULES_TRIGGERED_RISK_SCORE; + return NOT_IN_BLOCKCHAIN_RISK_SCORE; } if (error?.response?.status === 429) { diff --git a/indexer/packages/compliance/src/index.ts b/indexer/packages/compliance/src/index.ts index b3a587079a..0fc7422a05 100644 --- a/indexer/packages/compliance/src/index.ts +++ b/indexer/packages/compliance/src/index.ts @@ -5,3 +5,4 @@ export * from './geoblocking/util'; export * from './types'; export * from './config'; export * from './constants'; +export * from './clients/elliptic-provider'; diff --git a/indexer/packages/postgres/__tests__/stores/compliance-data-table.test.ts b/indexer/packages/postgres/__tests__/stores/compliance-data-table.test.ts index 2802726c83..f620ca50a1 100644 --- a/indexer/packages/postgres/__tests__/stores/compliance-data-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/compliance-data-table.test.ts @@ -1,5 +1,6 @@ import { ComplianceDataFromDatabase, ComplianceProvider } from '../../src/types'; import * as ComplianceDataTable from '../../src/stores/compliance-table'; +import * as WalletTable from '../../src/stores/wallet-table'; import { clearData, migrate, @@ -9,6 +10,7 @@ import { blockedComplianceData, blockedAddress, nonBlockedComplianceData, + defaultWallet, } from '../helpers/constants'; import { DateTime } from 'luxon'; @@ -139,6 +141,29 @@ describe('Compliance data store', () => { expect(complianceData).toEqual(blockedComplianceData); }); + it('Successfully filters by onlyDydxAddressWithDeposit', async () => { + // Create two compliance entries, one with a corresponding wallet entry and another without + await Promise.all([ + WalletTable.create(defaultWallet), + ComplianceDataTable.create(nonBlockedComplianceData), + ComplianceDataTable.create({ + ...nonBlockedComplianceData, + address: 'not_dydx_address', + }), + ]); + + const complianceData: ComplianceDataFromDatabase[] = await ComplianceDataTable.findAll( + { + addressInWalletsTable: true, + }, + [], + { readReplica: true }, + ); + + expect(complianceData.length).toEqual(1); + expect(complianceData[0]).toEqual(nonBlockedComplianceData); + }); + it('Unable finds compliance data', async () => { const complianceData: ComplianceDataFromDatabase | undefined = await ComplianceDataTable.findByAddressAndProvider( diff --git a/indexer/packages/postgres/src/stores/compliance-table.ts b/indexer/packages/postgres/src/stores/compliance-table.ts index 162edff16d..d3d53c9bb3 100644 --- a/indexer/packages/postgres/src/stores/compliance-table.ts +++ b/indexer/packages/postgres/src/stores/compliance-table.ts @@ -13,6 +13,7 @@ import { } from '../helpers/stores-helpers'; import Transaction from '../helpers/transaction'; import ComplianceDataModel from '../models/compliance-data-model'; +import WalletModel from '../models/wallet-model'; import { ComplianceDataFromDatabase, ComplianceDataQueryConfig, @@ -34,6 +35,7 @@ export async function findAll( provider, blocked, limit, + addressInWalletsTable, }: ComplianceDataQueryConfig, requiredFields: QueryableField[], options: Options = DEFAULT_POSTGRES_OPTIONS, @@ -45,6 +47,7 @@ export async function findAll( provider, blocked, limit, + addressInWalletsTable, } as QueryConfig, requiredFields, ); @@ -70,6 +73,14 @@ export async function findAll( baseQuery = baseQuery.where(ComplianceDataColumns.blocked, blocked); } + if (addressInWalletsTable === true) { + baseQuery = baseQuery.innerJoin( + WalletModel.tableName, + `${ComplianceDataModel.tableName}.${ComplianceDataColumns.address}`, + '=', + `${WalletModel.tableName}.${WalletModel.idColumn}`); + } + if (options.orderBy !== undefined) { for (const [column, order] of options.orderBy) { baseQuery = baseQuery.orderBy( diff --git a/indexer/packages/postgres/src/types/query-types.ts b/indexer/packages/postgres/src/types/query-types.ts index c5c18cab71..3b5cd025e2 100644 --- a/indexer/packages/postgres/src/types/query-types.ts +++ b/indexer/packages/postgres/src/types/query-types.ts @@ -92,6 +92,7 @@ export enum QueryableField { REFEREE_ADDRESS = 'refereeAddress', KEY = 'key', TOKEN = 'token', + ADDRESS_IN_WALLETS_TABLE = 'addressInWalletsTable', } export interface QueryConfig { @@ -291,6 +292,7 @@ export interface ComplianceDataQueryConfig extends QueryConfig { [QueryableField.UPDATED_BEFORE_OR_AT]?: string, [QueryableField.PROVIDER]?: string, [QueryableField.BLOCKED]?: boolean, + [QueryableField.ADDRESS_IN_WALLETS_TABLE]?: boolean, } export interface ComplianceStatusQueryConfig extends QueryConfig { diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/compliance-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/compliance-controller.test.ts index 34e12bddaa..571abd389f 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/compliance-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/compliance-controller.test.ts @@ -9,7 +9,11 @@ import { } from '@dydxprotocol-indexer/postgres'; import { stats } from '@dydxprotocol-indexer/base'; import { complianceProvider } from '../../../../src/helpers/compliance/compliance-clients'; -import { ComplianceClientResponse, INDEXER_COMPLIANCE_BLOCKED_PAYLOAD } from '@dydxprotocol-indexer/compliance'; +import { + ComplianceClientResponse, + INDEXER_COMPLIANCE_BLOCKED_PAYLOAD, + NOT_IN_BLOCKCHAIN_RISK_SCORE, +} from '@dydxprotocol-indexer/compliance'; import { ratelimitRedis } from '../../../../src/caches/rate-limiters'; import { redis } from '@dydxprotocol-indexer/redis'; import { DateTime } from 'luxon'; @@ -257,5 +261,33 @@ describe('compliance-controller#V4', () => { { provider: complianceProvider.provider }, ); }); + + it('GET /screen for invalid address does not upsert compliance data', async () => { + const invalidAddress: string = 'invalidAddress'; + const notInBlockchainRiskScore: string = NOT_IN_BLOCKCHAIN_RISK_SCORE.toString(); + + jest.spyOn(complianceProvider.client, 'getComplianceResponse').mockImplementation( + (address: string): Promise => { + return Promise.resolve({ + address, + blocked, + riskScore: notInBlockchainRiskScore, + }); + }, + ); + + const response: any = await sendRequest({ + type: RequestMethod.GET, + path: `/v4/screen?address=${invalidAddress}`, + }); + + expect(response.body).toEqual({ + restricted: false, + reason: undefined, + }); + + const data = await ComplianceTable.findAll({}, [], {}); + expect(data).toHaveLength(0); + }); }); }); diff --git a/indexer/services/comlink/src/controllers/api/v4/compliance-controller.ts b/indexer/services/comlink/src/controllers/api/v4/compliance-controller.ts index 09b5989c67..f8f5bd23e1 100644 --- a/indexer/services/comlink/src/controllers/api/v4/compliance-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/compliance-controller.ts @@ -1,5 +1,9 @@ import { logger, stats, TooManyRequestsError } from '@dydxprotocol-indexer/base'; -import { ComplianceClientResponse, INDEXER_COMPLIANCE_BLOCKED_PAYLOAD } from '@dydxprotocol-indexer/compliance'; +import { + ComplianceClientResponse, + INDEXER_COMPLIANCE_BLOCKED_PAYLOAD, + NOT_IN_BLOCKCHAIN_RISK_SCORE, +} from '@dydxprotocol-indexer/compliance'; import { ComplianceDataCreateObject, ComplianceDataFromDatabase, ComplianceTable } from '@dydxprotocol-indexer/postgres'; import express from 'express'; import { checkSchema, matchedData } from 'express-validator'; @@ -85,6 +89,17 @@ export class ComplianceControllerHelper extends Controller { ComplianceClientResponse = await complianceProvider.client.getComplianceResponse( address, ); + // Don't upsert invalid addresses (address causing ellitic error) to compliance table. + // When the elliptic request fails with 404, getComplianceResponse returns + // riskScore=NOT_IN_BLOCKCHAIN_RISK_SCORE + if (response.riskScore === undefined || + Number(response.riskScore) === NOT_IN_BLOCKCHAIN_RISK_SCORE) { + return { + restricted: false, + reason: undefined, + }; + } + complianceData = await ComplianceTable.upsert({ ..._.omitBy(response, _.isUndefined) as ComplianceDataCreateObject, provider: complianceProvider.provider, diff --git a/indexer/services/roundtable/__tests__/tasks/update-compliance-data.test.ts b/indexer/services/roundtable/__tests__/tasks/update-compliance-data.test.ts index 9b5c2f4a62..e0493b2ec7 100644 --- a/indexer/services/roundtable/__tests__/tasks/update-compliance-data.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/update-compliance-data.test.ts @@ -678,6 +678,66 @@ describe('update-compliance-data', () => { config.MAX_COMPLIANCE_DATA_QUERY_PER_LOOP = defaultMaxQueries; }); + + it('Only updates old addresses that are in wallets table', async () => { + const rogueWallet: string = 'address_not_in_wallets'; + // Seed database with old compliance data, and set up subaccounts to not be active + // Create a compliance dataentry that is not in the wallets table + await Promise.all([ + setupComplianceData(config.MAX_COMPLIANCE_DATA_AGE_SECONDS * 2), + setupInitialSubaccounts(config.MAX_ACTIVE_COMPLIANCE_DATA_AGE_SECONDS * 2), + ]); + await ComplianceTable.create({ + ...testConstants.nonBlockedComplianceData, + address: rogueWallet, + }); + + const riskScore: string = '75.00'; + setupMockProvider( + mockProvider, + { [testConstants.defaultAddress]: { blocked: true, riskScore } }, + ); + + await updateComplianceDataTask(mockProvider); + + const updatedCompliancnceData: ComplianceDataFromDatabase[] = await ComplianceTable.findAll({ + address: [testConstants.defaultAddress], + }, [], {}); + const unchangedComplianceData: ComplianceDataFromDatabase[] = await ComplianceTable.findAll({ + address: [rogueWallet], + }, [], {}); + + expectUpdatedCompliance( + updatedCompliancnceData[0], + { + address: testConstants.defaultAddress, + blocked: true, + riskScore, + }, + mockProvider.provider, + ); + expectUpdatedCompliance( + unchangedComplianceData[0], + { + address: rogueWallet, + blocked: testConstants.nonBlockedComplianceData.blocked, + riskScore: testConstants.nonBlockedComplianceData.riskScore, + }, + mockProvider.provider, + ); + expectGaugeStats({ + activeAddresses: 0, + newAddresses: 0, + oldAddresses: 1, + addressesScreened: 1, + upserted: 1, + statusUpserted: 1, + activeAddressesWithStaleCompliance: 0, + inactiveAddressesWithStaleCompliance: 1, + }, + mockProvider.provider, + ); + }); }); async function setupComplianceData( diff --git a/indexer/services/roundtable/src/tasks/update-compliance-data.ts b/indexer/services/roundtable/src/tasks/update-compliance-data.ts index ba6be2e32b..04db96294c 100644 --- a/indexer/services/roundtable/src/tasks/update-compliance-data.ts +++ b/indexer/services/roundtable/src/tasks/update-compliance-data.ts @@ -1,7 +1,7 @@ import { STATS_NO_SAMPLING, delay, logger, stats, } from '@dydxprotocol-indexer/base'; -import { ComplianceClientResponse } from '@dydxprotocol-indexer/compliance'; +import { ComplianceClientResponse, NOT_IN_BLOCKCHAIN_RISK_SCORE } from '@dydxprotocol-indexer/compliance'; import { ComplianceDataColumns, ComplianceDataCreateObject, @@ -151,6 +151,7 @@ export default async function runTask( blocked: false, provider: complianceProvider.provider, updatedBeforeOrAt: ageThreshold, + addressInWalletsTable: true, }, [], { readReplica: true }, @@ -318,10 +319,19 @@ async function getComplianceData( return result.value; }, )); + const addressNotFoundResponses: + PromiseFulfilledResult[] = successResponses.filter( + (result: PromiseSettledResult): + result is PromiseFulfilledResult => { + // riskScore = NOT_IN_BLOCKCHAIN_RISK_SCORE denotes elliptic 404 responses + return result.status === 'fulfilled' && result.value.riskScore === NOT_IN_BLOCKCHAIN_RISK_SCORE.toString(); + }, + ); if (failedResponses.length > 0) { const addressesWithoutResponses: string[] = _.without( addresses, + // complianceResponses includes 404 responses ..._.map(complianceResponses, 'address'), ); stats.increment( @@ -337,6 +347,22 @@ async function getComplianceData( errors: failedResponses, }); } + + if (addressNotFoundResponses.length > 0) { + const notFoundAddresses = addressNotFoundResponses.map((result) => result.value.address); + + stats.increment( + `${config.SERVICE_NAME}.${taskName}.get_compliance_data_404`, + 1, + undefined, + { provider: complianceProvider.provider }, + ); + logger.error({ + at: 'updated-compliance-data#getComplianceData', + message: 'Failed to retrieve compliance data for the addresses due to elliptic 404', + addresses: notFoundAddresses, + }); + } stats.timing( `${config.SERVICE_NAME}.${taskName}.get_batch_compliance_data`, Date.now() - startBatch, From 0f214f1c7329d6af1ac0e41f7a85daeb9aef1eaa Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:12:12 -0400 Subject: [PATCH 004/120] enable username generation roundtable (backport #2361) (#2362) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- indexer/services/roundtable/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 9f0f00c487..42b66a4882 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -51,7 +51,7 @@ export const configSchema = { LOOPS_ENABLED_AGGREGATE_TRADING_REWARDS_DAILY: parseBoolean({ default: true }), LOOPS_ENABLED_AGGREGATE_TRADING_REWARDS_WEEKLY: parseBoolean({ default: true }), LOOPS_ENABLED_AGGREGATE_TRADING_REWARDS_MONTHLY: parseBoolean({ default: true }), - LOOPS_ENABLED_SUBACCOUNT_USERNAME_GENERATOR: parseBoolean({ default: false }), + LOOPS_ENABLED_SUBACCOUNT_USERNAME_GENERATOR: parseBoolean({ default: true }), LOOPS_ENABLED_LEADERBOARD_PNL_ALL_TIME: parseBoolean({ default: false }), LOOPS_ENABLED_LEADERBOARD_PNL_DAILY: parseBoolean({ default: false }), LOOPS_ENABLED_LEADERBOARD_PNL_WEEKLY: parseBoolean({ default: false }), From a47c3277fb6e3dd4c78910a792940490b9c3bcf2 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:25:29 -0400 Subject: [PATCH 005/120] Add current equity as a pnl tick. (backport #2335) (#2365) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../api/v4/vault-controller.test.ts | 118 ++++--- .../controllers/api/v4/vault-controller.ts | 313 +++++++++++------- 2 files changed, 271 insertions(+), 160 deletions(-) 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 c0a9fe6c6e..ff03a401f6 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 @@ -18,17 +18,22 @@ import request from 'supertest'; import { getFixedRepresentation, sendRequest } from '../../../helpers/helpers'; import config from '../../../../src/config'; import { DateTime } from 'luxon'; +import Big from 'big.js'; describe('vault-controller#V4', () => { const experimentVaultsPrevVal: string = config.EXPERIMENT_VAULTS; const experimentVaultMarketsPrevVal: string = config.EXPERIMENT_VAULT_MARKETS; + const latestBlockHeight: string = '25'; const currentBlockHeight: string = '7'; const twoHourBlockHeight: string = '5'; const twoDayBlockHeight: string = '3'; const currentTime: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 }); + const latestTime: DateTime = currentTime.plus({ second: 5 }); const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 }); const twoDaysAgo: DateTime = currentTime.minus({ day: 2 }); const initialFundingIndex: string = '10000'; + const vault1Equity: number = 159500; + const vault2Equity: number = 10000; beforeAll(async () => { await dbHelpers.migrate(); @@ -61,8 +66,33 @@ describe('vault-controller#V4', () => { time: currentTime.toISO(), blockHeight: currentBlockHeight, }), + BlockTable.create({ + ...testConstants.defaultBlock, + time: latestTime.toISO(), + blockHeight: latestBlockHeight, + }), ]); await SubaccountTable.create(testConstants.vaultSubaccount); + await Promise.all([ + PerpetualPositionTable.create( + testConstants.defaultPerpetualPosition, + ), + AssetPositionTable.upsert(testConstants.defaultAssetPosition), + AssetPositionTable.upsert({ + ...testConstants.defaultAssetPosition, + subaccountId: testConstants.vaultSubaccountId, + }), + FundingIndexUpdatesTable.create({ + ...testConstants.defaultFundingIndexUpdate, + fundingIndex: initialFundingIndex, + effectiveAtHeight: testConstants.createdHeight, + }), + FundingIndexUpdatesTable.create({ + ...testConstants.defaultFundingIndexUpdate, + eventId: testConstants.defaultTendermintEventId2, + effectiveAtHeight: twoDayBlockHeight, + }), + ]); }); afterEach(async () => { @@ -93,17 +123,25 @@ describe('vault-controller#V4', () => { expectedTicksIndex: number[], ) => { const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); + const finalTick: PnlTicksFromDatabase = { + ...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]], + equity: Big(vault1Equity).toFixed(), + blockHeight: latestBlockHeight, + blockTime: latestTime.toISO(), + createdAt: latestTime.toISO(), + }; const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`, }); + expect(response.body.megavaultPnl).toHaveLength(expectedTicksIndex.length + 1); expect(response.body.megavaultPnl).toEqual( expect.arrayContaining( expectedTicksIndex.map((index: number) => { return expect.objectContaining(createdPnlTicks[index]); - }), + }).concat([finalTick]), ), ); }); @@ -127,7 +165,6 @@ describe('vault-controller#V4', () => { ].join(','); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`, @@ -138,7 +175,15 @@ describe('vault-controller#V4', () => { totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 2).toString(), netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 2).toString(), }; + const finalTick: PnlTicksFromDatabase = { + ...expectedPnlTickBase, + equity: Big(vault1Equity).add(vault2Equity).toFixed(), + blockHeight: latestBlockHeight, + blockTime: latestTime.toISO(), + createdAt: latestTime.toISO(), + }; + expect(response.body.megavaultPnl).toHaveLength(expectedTicksIndex.length + 1); expect(response.body.megavaultPnl).toEqual( expect.arrayContaining( expectedTicksIndex.map((index: number) => { @@ -148,7 +193,7 @@ describe('vault-controller#V4', () => { blockHeight: createdPnlTicks[index].blockHeight, blockTime: createdPnlTicks[index].blockTime, }); - }), + }).concat([expect.objectContaining(finalTick)]), ), ); }); @@ -175,6 +220,13 @@ describe('vault-controller#V4', () => { expectedTicksIndex: number[], ) => { const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); + const finalTick: PnlTicksFromDatabase = { + ...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]], + equity: Big(vault1Equity).toFixed(), + blockHeight: latestBlockHeight, + blockTime: latestTime.toISO(), + createdAt: latestTime.toISO(), + }; const response: request.Response = await sendRequest({ type: RequestMethod.GET, @@ -182,13 +234,13 @@ describe('vault-controller#V4', () => { }); expect(response.body.vaultsPnl).toHaveLength(1); - + expect(response.body.vaultsPnl[0].historicalPnl).toHaveLength(expectedTicksIndex.length + 1); expect(response.body.vaultsPnl[0]).toEqual({ ticker: testConstants.defaultPerpetualMarket.ticker, historicalPnl: expect.arrayContaining( expectedTicksIndex.map((index: number) => { return expect.objectContaining(createdPnlTicks[index]); - }), + }).concat(finalTick), ), }); }); @@ -213,6 +265,20 @@ describe('vault-controller#V4', () => { ].join(','); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); + const finalTick1: PnlTicksFromDatabase = { + ...createdPnlTicks[expectedTicksIndex1[expectedTicksIndex1.length - 1]], + equity: Big(vault1Equity).toFixed(), + blockHeight: latestBlockHeight, + blockTime: latestTime.toISO(), + createdAt: latestTime.toISO(), + }; + const finalTick2: PnlTicksFromDatabase = { + ...createdPnlTicks[expectedTicksIndex2[expectedTicksIndex2.length - 1]], + equity: Big(vault2Equity).toFixed(), + blockHeight: latestBlockHeight, + blockTime: latestTime.toISO(), + createdAt: latestTime.toISO(), + }; const response: request.Response = await sendRequest({ type: RequestMethod.GET, @@ -223,14 +289,14 @@ describe('vault-controller#V4', () => { ticker: testConstants.defaultPerpetualMarket.ticker, historicalPnl: expectedTicksIndex1.map((index: number) => { return createdPnlTicks[index]; - }), + }).concat(finalTick1), }; const expectedVaultPnl2: VaultHistoricalPnl = { ticker: testConstants.defaultPerpetualMarket2.ticker, historicalPnl: expectedTicksIndex2.map((index: number) => { return createdPnlTicks[index]; - }), + }).concat(finalTick2), }; expect(response.body.vaultsPnl).toEqual( @@ -260,23 +326,6 @@ describe('vault-controller#V4', () => { }); it('Get /megavault/positions with 1 vault subaccount', async () => { - await Promise.all([ - PerpetualPositionTable.create( - testConstants.defaultPerpetualPosition, - ), - AssetPositionTable.upsert(testConstants.defaultAssetPosition), - FundingIndexUpdatesTable.create({ - ...testConstants.defaultFundingIndexUpdate, - fundingIndex: initialFundingIndex, - effectiveAtHeight: testConstants.createdHeight, - }), - FundingIndexUpdatesTable.create({ - ...testConstants.defaultFundingIndexUpdate, - eventId: testConstants.defaultTendermintEventId2, - effectiveAtHeight: twoDayBlockHeight, - }), - ]); - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/positions', @@ -334,27 +383,6 @@ describe('vault-controller#V4', () => { testConstants.defaultPerpetualMarket2.clobPairId, ].join(','); - await Promise.all([ - PerpetualPositionTable.create( - testConstants.defaultPerpetualPosition, - ), - AssetPositionTable.upsert(testConstants.defaultAssetPosition), - AssetPositionTable.upsert({ - ...testConstants.defaultAssetPosition, - subaccountId: testConstants.vaultSubaccountId, - }), - FundingIndexUpdatesTable.create({ - ...testConstants.defaultFundingIndexUpdate, - fundingIndex: initialFundingIndex, - effectiveAtHeight: testConstants.createdHeight, - }), - FundingIndexUpdatesTable.create({ - ...testConstants.defaultFundingIndexUpdate, - eventId: testConstants.defaultTendermintEventId2, - effectiveAtHeight: twoDayBlockHeight, - }), - ]); - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/positions', 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 0403242ca4..830980955d 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -23,6 +23,7 @@ import { FundingIndexUpdatesTable, PnlTickInterval, } from '@dydxprotocol-indexer/postgres'; +import Big from 'big.js'; import express from 'express'; import { checkSchema, matchedData } from 'express-validator'; import _ from 'lodash'; @@ -68,13 +69,38 @@ class VaultController extends Controller { async getMegavaultHistoricalPnl( @Query() resolution?: PnlTickInterval, ): Promise { - const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(resolution); + const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); + const [ + vaultPnlTicks, + vaultPositions, + latestBlock, + ] : [ + PnlTicksFromDatabase[], + Map, + BlockFromDatabase, + ] = await Promise.all([ + getVaultSubaccountPnlTicks(resolution), + getVaultPositions(vaultSubaccounts), + BlockTable.getLatest(), + ]); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight const aggregatedPnlTicks: Map = aggregatePnlTicks(vaultPnlTicks); + const currentEquity: string = Array.from(vaultPositions.values()) + .map((position: VaultPosition): string => { + return position.equity; + }).reduce((acc: string, curr: string): string => { + return (Big(acc).add(Big(curr))).toFixed(); + }, '0'); + const pnlTicksWithCurrentTick: PnlTicksFromDatabase[] = getPnlTicksWithCurrentTick( + currentEquity, + Array.from(aggregatedPnlTicks.values()), + latestBlock, + ); + return { - megavaultPnl: Array.from(aggregatedPnlTicks.values()).map( + megavaultPnl: pnlTicksWithCurrentTick.map( (pnlTick: PnlTicksFromDatabase) => { return pnlTicksToResponseObject(pnlTick); }), @@ -86,7 +112,19 @@ class VaultController extends Controller { @Query() resolution?: PnlTickInterval, ): Promise { const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); - const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(resolution); + const [ + vaultPnlTicks, + vaultPositions, + latestBlock, + ] : [ + PnlTicksFromDatabase[], + Map, + BlockFromDatabase, + ] = await Promise.all([ + getVaultSubaccountPnlTicks(resolution), + getVaultPositions(vaultSubaccounts), + BlockTable.getLatest(), + ]); const groupedVaultPnlTicks: VaultHistoricalPnl[] = _(vaultPnlTicks) .groupBy('subaccountId') @@ -102,9 +140,17 @@ class VaultController extends Controller { 'a perpetual market.'); } + const vaultPosition: VaultPosition | undefined = vaultPositions.get(subaccountId); + const currentEquity: string = vaultPosition === undefined ? '0' : vaultPosition.equity; + const pnlTicksWithCurrentTick: PnlTicksFromDatabase[] = getPnlTicksWithCurrentTick( + currentEquity, + pnlTicks, + latestBlock, + ); + return { ticker: market.ticker, - historicalPnl: pnlTicks, + historicalPnl: pnlTicksWithCurrentTick, }; }) .values() @@ -118,120 +164,11 @@ class VaultController extends Controller { @Get('/megavault/positions') async getMegavaultPositions(): Promise { const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); - const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts); - if (vaultSubaccountIds.length === 0) { - return { - positions: [], - }; - } - - const [ - subaccounts, - assets, - openPerpetualPositions, - assetPositions, - markets, - latestBlock, - ]: [ - SubaccountFromDatabase[], - AssetFromDatabase[], - PerpetualPositionFromDatabase[], - AssetPositionFromDatabase[], - MarketFromDatabase[], - BlockFromDatabase | undefined, - ] = await Promise.all([ - SubaccountTable.findAll( - { - id: vaultSubaccountIds, - }, - [], - ), - AssetTable.findAll( - {}, - [], - ), - PerpetualPositionTable.findAll( - { - subaccountId: vaultSubaccountIds, - status: [PerpetualPositionStatus.OPEN], - }, - [], - ), - AssetPositionTable.findAll( - { - subaccountId: vaultSubaccountIds, - assetId: [USDC_ASSET_ID], - }, - [], - ), - MarketTable.findAll( - {}, - [], - ), - BlockTable.getLatest(), - ]); - - const latestFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable - .findFundingIndexMap( - latestBlock.blockHeight, - ); - const assetPositionsBySubaccount: - { [subaccountId: string]: AssetPositionFromDatabase[] } = _.groupBy( - assetPositions, - 'subaccountId', - ); - const openPerpetualPositionsBySubaccount: - { [subaccountId: string]: PerpetualPositionFromDatabase[] } = _.groupBy( - openPerpetualPositions, - 'subaccountId', - ); - const assetIdToAsset: AssetById = _.keyBy( - assets, - AssetColumns.id, - ); - - const vaultPositions: VaultPosition[] = await Promise.all( - subaccounts.map(async (subaccount: SubaccountFromDatabase) => { - const perpetualMarket: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher - .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id]); - if (perpetualMarket === undefined) { - throw new Error( - `Vault clob pair id ${vaultSubaccounts[subaccount.id]} does not correspond to a ` + - 'perpetual market.'); - } - const lastUpdatedFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable - .findFundingIndexMap( - subaccount.updatedAtHeight, - ); - - const subaccountResponse: SubaccountResponseObject = getSubaccountResponse( - subaccount, - openPerpetualPositionsBySubaccount[subaccount.id] || [], - assetPositionsBySubaccount[subaccount.id] || [], - assets, - markets, - perpetualMarketRefresher.getPerpetualMarketsMap(), - latestBlock.blockHeight, - latestFundingIndexMap, - lastUpdatedFundingIndexMap, - ); - - return { - ticker: perpetualMarket.ticker, - assetPosition: subaccountResponse.assetPositions[ - assetIdToAsset[USDC_ASSET_ID].symbol - ], - perpetualPosition: subaccountResponse.openPerpetualPositions[ - perpetualMarket.ticker - ] || undefined, - equity: subaccountResponse.equity, - }; - }), - ); + const vaultPositions: Map = await getVaultPositions(vaultSubaccounts); return { - positions: _.sortBy(vaultPositions, 'ticker'), + positions: _.sortBy(Array.from(vaultPositions.values()), 'ticker'), }; } } @@ -371,6 +308,152 @@ async function getVaultSubaccountPnlTicks( return pnlTicks; } +async function getVaultPositions( + vaultSubaccounts: VaultMapping, +): Promise> { + const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts); + if (vaultSubaccountIds.length === 0) { + return new Map(); + } + + const [ + subaccounts, + assets, + openPerpetualPositions, + assetPositions, + markets, + latestBlock, + ]: [ + SubaccountFromDatabase[], + AssetFromDatabase[], + PerpetualPositionFromDatabase[], + AssetPositionFromDatabase[], + MarketFromDatabase[], + BlockFromDatabase | undefined, + ] = await Promise.all([ + SubaccountTable.findAll( + { + id: vaultSubaccountIds, + }, + [], + ), + AssetTable.findAll( + {}, + [], + ), + PerpetualPositionTable.findAll( + { + subaccountId: vaultSubaccountIds, + status: [PerpetualPositionStatus.OPEN], + }, + [], + ), + AssetPositionTable.findAll( + { + subaccountId: vaultSubaccountIds, + assetId: [USDC_ASSET_ID], + }, + [], + ), + MarketTable.findAll( + {}, + [], + ), + BlockTable.getLatest(), + ]); + + const latestFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable + .findFundingIndexMap( + latestBlock.blockHeight, + ); + const assetPositionsBySubaccount: + { [subaccountId: string]: AssetPositionFromDatabase[] } = _.groupBy( + assetPositions, + 'subaccountId', + ); + const openPerpetualPositionsBySubaccount: + { [subaccountId: string]: PerpetualPositionFromDatabase[] } = _.groupBy( + openPerpetualPositions, + 'subaccountId', + ); + const assetIdToAsset: AssetById = _.keyBy( + assets, + AssetColumns.id, + ); + + const vaultPositionsAndSubaccountId: { + position: VaultPosition, + subaccountId: string, + }[] = await Promise.all( + subaccounts.map(async (subaccount: SubaccountFromDatabase) => { + const perpetualMarket: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher + .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id]); + if (perpetualMarket === undefined) { + throw new Error( + `Vault clob pair id ${vaultSubaccounts[subaccount.id]} does not correspond to a ` + + 'perpetual market.'); + } + const lastUpdatedFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable + .findFundingIndexMap( + subaccount.updatedAtHeight, + ); + + const subaccountResponse: SubaccountResponseObject = getSubaccountResponse( + subaccount, + openPerpetualPositionsBySubaccount[subaccount.id] || [], + assetPositionsBySubaccount[subaccount.id] || [], + assets, + markets, + perpetualMarketRefresher.getPerpetualMarketsMap(), + latestBlock.blockHeight, + latestFundingIndexMap, + lastUpdatedFundingIndexMap, + ); + + return { + position: { + ticker: perpetualMarket.ticker, + assetPosition: subaccountResponse.assetPositions[ + assetIdToAsset[USDC_ASSET_ID].symbol + ], + perpetualPosition: subaccountResponse.openPerpetualPositions[ + perpetualMarket.ticker + ] || undefined, + equity: subaccountResponse.equity, + }, + subaccountId: subaccount.id, + }; + }), + ); + + return new Map(vaultPositionsAndSubaccountId.map( + (obj: { position: VaultPosition, subaccountId: string }) : [string, VaultPosition] => { + return [ + obj.subaccountId, + obj.position, + ]; + }, + )); +} + +function getPnlTicksWithCurrentTick( + equity: string, + pnlTicks: PnlTicksFromDatabase[], + latestBlock: BlockFromDatabase, +): PnlTicksFromDatabase[] { + if (pnlTicks.length === 0) { + return []; + } + const currentTick: PnlTicksFromDatabase = { + ...pnlTicks[pnlTicks.length - 1], + equity, + blockHeight: latestBlock.blockHeight, + blockTime: latestBlock.time, + createdAt: latestBlock.time, + }; + return pnlTicks.concat([currentTick]); +} + // TODO(TRA-570): Placeholder for getting vault subaccount ids until vault table is added. function getVaultSubaccountsFromConfig(): VaultMapping { if (config.EXPERIMENT_VAULTS === '' && config.EXPERIMENT_VAULT_MARKETS === '') { From 9875783bc049ac884b71e8e53a991fd9853732b9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:57:42 -0400 Subject: [PATCH 006/120] Use vault table rather than placeholder config flags to fetch vaults. (backport #2364) (#2367) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../api/v4/vault-controller.test.ts | 94 ++++++++++--------- indexer/services/comlink/src/config.ts | 5 - .../controllers/api/v4/vault-controller.ts | 41 ++++---- 3 files changed, 73 insertions(+), 67 deletions(-) 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 ff03a401f6..488435f8e7 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 @@ -12,17 +12,15 @@ import { AssetPositionTable, FundingIndexUpdatesTable, PnlTicksFromDatabase, + VaultTable, } from '@dydxprotocol-indexer/postgres'; import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; import request from 'supertest'; import { getFixedRepresentation, sendRequest } from '../../../helpers/helpers'; -import config from '../../../../src/config'; import { DateTime } from 'luxon'; import Big from 'big.js'; describe('vault-controller#V4', () => { - const experimentVaultsPrevVal: string = config.EXPERIMENT_VAULTS; - const experimentVaultMarketsPrevVal: string = config.EXPERIMENT_VAULT_MARKETS; const latestBlockHeight: string = '25'; const currentBlockHeight: string = '7'; const twoHourBlockHeight: string = '5'; @@ -45,8 +43,6 @@ describe('vault-controller#V4', () => { describe('GET /v1', () => { beforeEach(async () => { - config.EXPERIMENT_VAULTS = testConstants.defaultPnlTick.subaccountId; - config.EXPERIMENT_VAULT_MARKETS = testConstants.defaultPerpetualMarket.clobPairId; await testMocks.seedData(); await perpetualMarketRefresher.updatePerpetualMarkets(); await liquidityTierRefresher.updateLiquidityTiers(); @@ -96,15 +92,10 @@ describe('vault-controller#V4', () => { }); afterEach(async () => { - config.EXPERIMENT_VAULTS = experimentVaultsPrevVal; - config.EXPERIMENT_VAULT_MARKETS = experimentVaultMarketsPrevVal; await dbHelpers.clearData(); }); it('Get /megavault/historicalPnl with no vault subaccounts', async () => { - config.EXPERIMENT_VAULTS = ''; - config.EXPERIMENT_VAULT_MARKETS = ''; - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/historicalPnl', @@ -122,6 +113,11 @@ describe('vault-controller#V4', () => { queryParam: string, expectedTicksIndex: number[], ) => { + await VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultSubaccount.address, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const finalTick: PnlTicksFromDatabase = { ...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]], @@ -155,14 +151,18 @@ describe('vault-controller#V4', () => { queryParam: string, expectedTicksIndex: number[], ) => { - config.EXPERIMENT_VAULTS = [ - testConstants.defaultPnlTick.subaccountId, - testConstants.vaultSubaccountId, - ].join(','); - config.EXPERIMENT_VAULT_MARKETS = [ - testConstants.defaultPerpetualMarket.clobPairId, - testConstants.defaultPerpetualMarket2.clobPairId, - ].join(','); + await Promise.all([ + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultAddress, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }), + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.vaultAddress, + clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, + }), + ]); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const response: request.Response = await sendRequest({ @@ -199,9 +199,6 @@ describe('vault-controller#V4', () => { }); it('Get /vaults/historicalPnl with no vault subaccounts', async () => { - config.EXPERIMENT_VAULTS = ''; - config.EXPERIMENT_VAULT_MARKETS = ''; - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/vaults/historicalPnl', @@ -219,6 +216,11 @@ describe('vault-controller#V4', () => { queryParam: string, expectedTicksIndex: number[], ) => { + await VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultAddress, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const finalTick: PnlTicksFromDatabase = { ...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]], @@ -255,15 +257,18 @@ describe('vault-controller#V4', () => { expectedTicksIndex1: number[], expectedTicksIndex2: number[], ) => { - config.EXPERIMENT_VAULTS = [ - testConstants.defaultPnlTick.subaccountId, - testConstants.vaultSubaccountId, - ].join(','); - config.EXPERIMENT_VAULT_MARKETS = [ - testConstants.defaultPerpetualMarket.clobPairId, - testConstants.defaultPerpetualMarket2.clobPairId, - ].join(','); - + await Promise.all([ + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultAddress, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }), + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.vaultAddress, + clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, + }), + ]); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const finalTick1: PnlTicksFromDatabase = { ...createdPnlTicks[expectedTicksIndex1[expectedTicksIndex1.length - 1]], @@ -312,9 +317,6 @@ describe('vault-controller#V4', () => { }); it('Get /megavault/positions with no vault subaccount', async () => { - config.EXPERIMENT_VAULTS = ''; - config.EXPERIMENT_VAULT_MARKETS = ''; - const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/positions', @@ -326,6 +328,11 @@ describe('vault-controller#V4', () => { }); it('Get /megavault/positions with 1 vault subaccount', async () => { + await VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultAddress, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }); const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/positions', @@ -374,15 +381,18 @@ describe('vault-controller#V4', () => { }); it('Get /megavault/positions with 2 vault subaccount, 1 with no perpetual', async () => { - config.EXPERIMENT_VAULTS = [ - testConstants.defaultPnlTick.subaccountId, - testConstants.vaultSubaccountId, - ].join(','); - config.EXPERIMENT_VAULT_MARKETS = [ - testConstants.defaultPerpetualMarket.clobPairId, - testConstants.defaultPerpetualMarket2.clobPairId, - ].join(','); - + await Promise.all([ + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultAddress, + clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + }), + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.vaultAddress, + clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, + }), + ]); const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: '/v4/vault/v1/megavault/positions', diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index 9591c64eb0..43d2c81222 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -56,11 +56,6 @@ export const configSchema = { // Expose setting compliance status, only set to true in dev/staging. EXPOSE_SET_COMPLIANCE_ENDPOINT: parseBoolean({ default: false }), - // TODO(TRA-570): Placeholder data for vaults and matching set of markets for each vault until - // vaults table is added. - EXPERIMENT_VAULTS: parseString({ default: '' }), - EXPERIMENT_VAULT_MARKETS: parseString({ default: '' }), - // Affiliates config VOLUME_ELIGIBILITY_THRESHOLD: parseInteger({ default: 10_000 }), 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 830980955d..e377f40c9b 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -22,6 +22,8 @@ import { BlockFromDatabase, FundingIndexUpdatesTable, PnlTickInterval, + VaultTable, + VaultFromDatabase, } from '@dydxprotocol-indexer/postgres'; import Big from 'big.js'; import express from 'express'; @@ -57,8 +59,6 @@ import { const router: express.Router = express.Router(); const controllerName: string = 'vault-controller'; -// TODO(TRA-570): Placeholder interface for mapping of vault subaccounts to tickers until vaults -// table is added. interface VaultMapping { [subaccountId: string]: string, } @@ -69,7 +69,7 @@ class VaultController extends Controller { async getMegavaultHistoricalPnl( @Query() resolution?: PnlTickInterval, ): Promise { - const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); + const vaultSubaccounts: VaultMapping = await getVaultMapping(); const [ vaultPnlTicks, vaultPositions, @@ -79,7 +79,7 @@ class VaultController extends Controller { Map, BlockFromDatabase, ] = await Promise.all([ - getVaultSubaccountPnlTicks(resolution), + getVaultSubaccountPnlTicks(vaultSubaccounts, resolution), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), ]); @@ -111,7 +111,7 @@ class VaultController extends Controller { async getVaultsHistoricalPnl( @Query() resolution?: PnlTickInterval, ): Promise { - const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); + const vaultSubaccounts: VaultMapping = await getVaultMapping(); const [ vaultPnlTicks, vaultPositions, @@ -121,7 +121,7 @@ class VaultController extends Controller { Map, BlockFromDatabase, ] = await Promise.all([ - getVaultSubaccountPnlTicks(resolution), + getVaultSubaccountPnlTicks(vaultSubaccounts, resolution), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), ]); @@ -163,7 +163,7 @@ class VaultController extends Controller { @Get('/megavault/positions') async getMegavaultPositions(): Promise { - const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); + const vaultSubaccounts: VaultMapping = await getVaultMapping(); const vaultPositions: Map = await getVaultPositions(vaultSubaccounts); @@ -286,9 +286,10 @@ router.get( }); async function getVaultSubaccountPnlTicks( + vaultSubaccounts: VaultMapping, resolution?: PnlTickInterval, ): Promise { - const vaultSubaccountIds: string[] = _.keys(getVaultSubaccountsFromConfig()); + const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts); if (vaultSubaccountIds.length === 0) { return []; } @@ -454,19 +455,19 @@ function getPnlTicksWithCurrentTick( return pnlTicks.concat([currentTick]); } -// TODO(TRA-570): Placeholder for getting vault subaccount ids until vault table is added. -function getVaultSubaccountsFromConfig(): VaultMapping { - if (config.EXPERIMENT_VAULTS === '' && config.EXPERIMENT_VAULT_MARKETS === '') { - return {}; - } - const vaultSubaccountIds: string[] = config.EXPERIMENT_VAULTS.split(','); - const vaultClobPairIds: string[] = config.EXPERIMENT_VAULT_MARKETS.split(','); - if (vaultSubaccountIds.length !== vaultClobPairIds.length) { - throw new Error('Expected number of vaults to match number of markets'); - } +async function getVaultMapping(): Promise { + const vaults: VaultFromDatabase[] = await VaultTable.findAll( + {}, + [], + {}, + ); return _.zipObject( - vaultSubaccountIds, - vaultClobPairIds, + vaults.map((vault: VaultFromDatabase): string => { + return SubaccountTable.uuid(vault.address, 0); + }), + vaults.map((vault: VaultFromDatabase): string => { + return vault.clobPairId; + }), ); } From d0347164128507d9964a3c67e5631698275a15c1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:00:06 -0400 Subject: [PATCH 007/120] Add sql script latency metrics (backport #2356) (#2371) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- .../__tests__/handlers/funding-handler.test.ts | 8 ++++++++ .../services/ender/src/handlers/asset-handler.ts | 8 ++++++++ .../ender/src/handlers/funding-handler.ts | 7 +++++++ .../ender/src/handlers/liquidity-tier-handler.ts | 8 ++++++++ .../src/handlers/markets/market-create-handler.ts | 11 +++++++++-- .../src/handlers/markets/market-modify-handler.ts | 12 ++++++++++-- .../markets/market-price-update-handler.ts | 10 +++++++++- .../handlers/order-fills/deleveraging-handler.ts | 9 ++++++++- .../handlers/order-fills/liquidation-handler.ts | 8 ++++++++ .../src/handlers/order-fills/order-handler.ts | 9 +++++++++ .../src/handlers/perpetual-market-handler.ts | 8 ++++++++ .../conditional-order-placement-handler.ts | 8 ++++++++ .../conditional-order-triggered-handler.ts | 9 ++++++++- .../stateful-order-placement-handler.ts | 11 ++++++++++- .../stateful-order-removal-handler.ts | 10 +++++++++- .../src/handlers/subaccount-update-handler.ts | 8 ++++++++ .../ender/src/handlers/trading-rewards-handler.ts | 8 ++++++++ .../ender/src/handlers/transfer-handler.ts | 8 ++++++++ .../src/handlers/update-clob-pair-handler.ts | 8 ++++++++ .../src/handlers/update-perpetual-handler.ts | 8 ++++++++ .../dydx_block_processor_ordered_handlers.sql | 15 +++++++++++++++ .../dydx_block_processor_unordered_handlers.sql | 15 +++++++++++++++ 22 files changed, 197 insertions(+), 9 deletions(-) diff --git a/indexer/services/ender/__tests__/handlers/funding-handler.test.ts b/indexer/services/ender/__tests__/handlers/funding-handler.test.ts index 669810deb9..afe0df78fa 100644 --- a/indexer/services/ender/__tests__/handlers/funding-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/funding-handler.test.ts @@ -233,6 +233,14 @@ describe('fundingHandler', () => { })); expect(stats.gauge).toHaveBeenCalledWith('ender.funding_index_update_event', 0.1, { ticker: 'BTC-USD' }); expect(stats.gauge).toHaveBeenCalledWith('ender.funding_index_update', 0.1, { ticker: 'BTC-USD' }); + expect(stats.timing).toHaveBeenCalledWith( + 'ender.handle_funding_event.sql_latency', + expect.any(Number), + { + className: 'FundingHandler', + eventType: 'FundingEvent', + }, + ); }); it('successfully processes and clears cache for a new funding rate', async () => { diff --git a/indexer/services/ender/src/handlers/asset-handler.ts b/indexer/services/ender/src/handlers/asset-handler.ts index b505f6af5c..34cd516050 100644 --- a/indexer/services/ender/src/handlers/asset-handler.ts +++ b/indexer/services/ender/src/handlers/asset-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { AssetFromDatabase, AssetModel, @@ -6,6 +7,7 @@ import { import { AssetCreateEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../config'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -18,6 +20,12 @@ export class AssetCreationHandler extends Handler { // eslint-disable-next-line @typescript-eslint/require-await public async internalHandle(resultRow: pg.QueryResultRow): Promise { + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_asset_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); const asset: AssetFromDatabase = AssetModel.fromJson( resultRow.asset) as AssetFromDatabase; assetRefresher.addAsset(asset); diff --git a/indexer/services/ender/src/handlers/funding-handler.ts b/indexer/services/ender/src/handlers/funding-handler.ts index b05af85806..5485dfe84c 100644 --- a/indexer/services/ender/src/handlers/funding-handler.ts +++ b/indexer/services/ender/src/handlers/funding-handler.ts @@ -141,6 +141,13 @@ export class FundingHandler extends Handler { }); stats.increment(`${config.SERVICE_NAME}.handle_funding_event.failure`, 1); } + + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_funding_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); } await Promise.all(promises); diff --git a/indexer/services/ender/src/handlers/liquidity-tier-handler.ts b/indexer/services/ender/src/handlers/liquidity-tier-handler.ts index 92e1f7a901..b36df1812a 100644 --- a/indexer/services/ender/src/handlers/liquidity-tier-handler.ts +++ b/indexer/services/ender/src/handlers/liquidity-tier-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { LiquidityTiersFromDatabase, LiquidityTiersModel, @@ -9,6 +10,7 @@ import { LiquidityTierUpsertEventV1, LiquidityTierUpsertEventV2 } from '@dydxpro import _ from 'lodash'; import * as pg from 'pg'; +import config from '../config'; import { generatePerpetualMarketMessage } from '../helpers/kafka-helper'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -21,6 +23,12 @@ export class LiquidityTierHandlerBase extends Handler { // eslint-disable-next-line @typescript-eslint/require-await public async internalHandle(resultRow: pg.QueryResultRow): Promise { + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_liquidity_tier_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); const liquidityTier: LiquidityTiersFromDatabase = LiquidityTiersModel.fromJson( resultRow.liquidity_tier, ) as LiquidityTiersFromDatabase; diff --git a/indexer/services/ender/src/handlers/markets/market-create-handler.ts b/indexer/services/ender/src/handlers/markets/market-create-handler.ts index 6f539e3665..aa8bc571b3 100644 --- a/indexer/services/ender/src/handlers/markets/market-create-handler.ts +++ b/indexer/services/ender/src/handlers/markets/market-create-handler.ts @@ -1,7 +1,8 @@ -import { logger } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { MarketEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../../config'; import { ConsolidatedKafkaEvent } from '../../lib/types'; import { Handler } from '../handler'; @@ -14,12 +15,18 @@ export class MarketCreateHandler extends Handler { } // eslint-disable-next-line @typescript-eslint/require-await - public async internalHandle(_: pg.QueryResultRow): Promise { + public async internalHandle(resultRow: pg.QueryResultRow): Promise { logger.info({ at: 'MarketCreateHandler#handle', message: 'Received MarketEvent with MarketCreate.', event: this.event, }); + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_market_create_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); return []; } diff --git a/indexer/services/ender/src/handlers/markets/market-modify-handler.ts b/indexer/services/ender/src/handlers/markets/market-modify-handler.ts index eeee9188e3..88f416ef17 100644 --- a/indexer/services/ender/src/handlers/markets/market-modify-handler.ts +++ b/indexer/services/ender/src/handlers/markets/market-modify-handler.ts @@ -1,7 +1,8 @@ -import { logger } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { MarketEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../../config'; import { ConsolidatedKafkaEvent } from '../../lib/types'; import { Handler } from '../handler'; @@ -14,13 +15,20 @@ export class MarketModifyHandler extends Handler { } // eslint-disable-next-line @typescript-eslint/require-await - public async internalHandle(_: pg.QueryResultRow): Promise { + public async internalHandle(resultRow: pg.QueryResultRow): Promise { logger.info({ at: 'MarketModifyHandler#handle', message: 'Received MarketEvent with MarketModify.', event: this.event, }); + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_market_modify_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); + return []; } } diff --git a/indexer/services/ender/src/handlers/markets/market-price-update-handler.ts b/indexer/services/ender/src/handlers/markets/market-price-update-handler.ts index 56c9978fd9..d11dd89ade 100644 --- a/indexer/services/ender/src/handlers/markets/market-price-update-handler.ts +++ b/indexer/services/ender/src/handlers/markets/market-price-update-handler.ts @@ -1,4 +1,4 @@ -import { logger } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { MarketFromDatabase, OraclePriceFromDatabase, @@ -8,6 +8,7 @@ import { import { MarketEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../../config'; import { generateOraclePriceContents } from '../../helpers/kafka-helper'; import { ConsolidatedKafkaEvent, @@ -35,6 +36,13 @@ export class MarketPriceUpdateHandler extends Handler { const oraclePrice: OraclePriceFromDatabase = OraclePriceModel.fromJson( resultRow.oracle_price) as OraclePriceFromDatabase; + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_market_price_update_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); + return [ this.generateKafkaEvent( oraclePrice, market.pair, diff --git a/indexer/services/ender/src/handlers/order-fills/deleveraging-handler.ts b/indexer/services/ender/src/handlers/order-fills/deleveraging-handler.ts index ea8687f5d0..ce352487db 100644 --- a/indexer/services/ender/src/handlers/order-fills/deleveraging-handler.ts +++ b/indexer/services/ender/src/handlers/order-fills/deleveraging-handler.ts @@ -1,4 +1,4 @@ -import { logger } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { FillFromDatabase, FillModel, @@ -15,6 +15,7 @@ import { import { DeleveragingEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../../config'; import { SUBACCOUNT_ORDER_FILL_EVENT_TYPE } from '../../constants'; import { annotateWithPnl, convertPerpetualPosition } from '../../helpers/kafka-helper'; import { ConsolidatedKafkaEvent } from '../../lib/types'; @@ -95,6 +96,12 @@ export class DeleveragingHandler extends AbstractOrderFillHandler { + public async internalHandle(resultRow: pg.QueryResultRow): Promise { let order: IndexerOrder; // TODO(IND-334): Remove after deprecating StatefulOrderPlacementEvent if (this.event.orderPlace !== undefined) { @@ -40,6 +43,12 @@ export class StatefulOrderPlacementHandler } else { order = this.event.longTermOrderPlacement!.order!; } + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_stateful_order_placement_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); return this.createKafkaEvents(order); } diff --git a/indexer/services/ender/src/handlers/stateful-order/stateful-order-removal-handler.ts b/indexer/services/ender/src/handlers/stateful-order/stateful-order-removal-handler.ts index 02715d1021..e0667e5f6e 100644 --- a/indexer/services/ender/src/handlers/stateful-order/stateful-order-removal-handler.ts +++ b/indexer/services/ender/src/handlers/stateful-order/stateful-order-removal-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { OrderTable, } from '@dydxprotocol-indexer/postgres'; @@ -10,6 +11,7 @@ import { } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../../config'; import { ConsolidatedKafkaEvent } from '../../lib/types'; import { AbstractStatefulOrderHandler } from '../abstract-stateful-order-handler'; @@ -24,8 +26,14 @@ export class StatefulOrderRemovalHandler extends } // eslint-disable-next-line @typescript-eslint/require-await - public async internalHandle(_: pg.QueryResultRow): Promise { + public async internalHandle(resultRow: pg.QueryResultRow): Promise { const orderIdProto: IndexerOrderId = this.event.orderRemoval!.removedOrderId!; + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_stateful_order_removal_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); return this.createKafkaEvents(orderIdProto); } diff --git a/indexer/services/ender/src/handlers/subaccount-update-handler.ts b/indexer/services/ender/src/handlers/subaccount-update-handler.ts index 157cbcdfed..af3f60b9eb 100644 --- a/indexer/services/ender/src/handlers/subaccount-update-handler.ts +++ b/indexer/services/ender/src/handlers/subaccount-update-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { AssetPositionFromDatabase, AssetPositionModel, @@ -16,6 +17,7 @@ import { import _ from 'lodash'; import * as pg from 'pg'; +import config from '../config'; import { SUBACCOUNT_ORDER_FILL_EVENT_TYPE } from '../constants'; import { addPositionsToContents, annotateWithPnl } from '../helpers/kafka-helper'; import { SubaccountUpdate } from '../lib/translated-types'; @@ -61,6 +63,12 @@ export class SubaccountUpdateHandler extends Handler { marketIdToMarket[marketId], ); } + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_subaccount_update_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); return [ this.generateConsolidatedKafkaEvent( diff --git a/indexer/services/ender/src/handlers/trading-rewards-handler.ts b/indexer/services/ender/src/handlers/trading-rewards-handler.ts index 40cb63b474..85951a349e 100644 --- a/indexer/services/ender/src/handlers/trading-rewards-handler.ts +++ b/indexer/services/ender/src/handlers/trading-rewards-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { SubaccountMessageContents, TradingRewardFromDatabase, @@ -8,6 +9,7 @@ import { TradingRewardsEventV1 } from '@dydxprotocol-indexer/v4-protos'; import _ from 'lodash'; import * as pg from 'pg'; +import config from '../config'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -21,6 +23,12 @@ export class TradingRewardsHandler extends Handler { // eslint-disable-next-line @typescript-eslint/require-await public async internalHandle(resultRow: pg.QueryResultRow): Promise { + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_trading_rewards_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); const tradingRewards: TradingRewardFromDatabase[] = _.map( resultRow.trading_rewards, (tradingReward: object) => { diff --git a/indexer/services/ender/src/handlers/transfer-handler.ts b/indexer/services/ender/src/handlers/transfer-handler.ts index ff95eff157..ae15612534 100644 --- a/indexer/services/ender/src/handlers/transfer-handler.ts +++ b/indexer/services/ender/src/handlers/transfer-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { AssetFromDatabase, AssetModel, @@ -8,6 +9,7 @@ import { import { TransferEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../config'; import { generateTransferContents } from '../helpers/kafka-helper'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -22,6 +24,12 @@ export class TransferHandler extends Handler { // eslint-disable-next-line @typescript-eslint/require-await public async internalHandle(resultRow: pg.QueryResultRow): Promise { + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_transfer_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); const asset: AssetFromDatabase = AssetModel.fromJson( resultRow.asset) as AssetFromDatabase; const transfer: TransferFromDatabase = TransferModel.fromJson( diff --git a/indexer/services/ender/src/handlers/update-clob-pair-handler.ts b/indexer/services/ender/src/handlers/update-clob-pair-handler.ts index 0840835227..9875e2d2f2 100644 --- a/indexer/services/ender/src/handlers/update-clob-pair-handler.ts +++ b/indexer/services/ender/src/handlers/update-clob-pair-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { PerpetualMarketFromDatabase, PerpetualMarketModel, @@ -6,6 +7,7 @@ import { import { UpdateClobPairEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../config'; import { generatePerpetualMarketMessage } from '../helpers/kafka-helper'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -19,6 +21,12 @@ export class UpdateClobPairHandler extends Handler { // eslint-disable-next-line @typescript-eslint/require-await public async internalHandle(resultRow: pg.QueryResultRow): Promise { + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_clob_pair_update_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); const perpetualMarket: PerpetualMarketFromDatabase = PerpetualMarketModel.fromJson( resultRow.perpetual_market) as PerpetualMarketFromDatabase; diff --git a/indexer/services/ender/src/handlers/update-perpetual-handler.ts b/indexer/services/ender/src/handlers/update-perpetual-handler.ts index c3a9175b21..d17d48e130 100644 --- a/indexer/services/ender/src/handlers/update-perpetual-handler.ts +++ b/indexer/services/ender/src/handlers/update-perpetual-handler.ts @@ -1,3 +1,4 @@ +import { stats } from '@dydxprotocol-indexer/base'; import { PerpetualMarketFromDatabase, perpetualMarketRefresher, @@ -6,6 +7,7 @@ import { import { UpdatePerpetualEventV1 } from '@dydxprotocol-indexer/v4-protos'; import * as pg from 'pg'; +import config from '../config'; import { generatePerpetualMarketMessage } from '../helpers/kafka-helper'; import { ConsolidatedKafkaEvent } from '../lib/types'; import { Handler } from './handler'; @@ -23,6 +25,12 @@ export class UpdatePerpetualHandler extends Handler { resultRow.perpetual_market) as PerpetualMarketFromDatabase; await perpetualMarketRefresher.upsertPerpetualMarket(perpetualMarket); + // Handle latency from resultRow + stats.timing( + `${config.SERVICE_NAME}.handle_update_perpetual_event.sql_latency`, + Number(resultRow.latency), + this.generateTimingStatsOptions(), + ); return [ this.generateConsolidatedMarketKafkaEvent( diff --git a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql index 12c818ecb6..1a6235d850 100644 --- a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql +++ b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql @@ -23,11 +23,16 @@ DECLARE event_index int; transaction_index int; event_data jsonb; + -- Latency tracking variables + event_start_time timestamp; + event_end_time timestamp; + event_latency interval; BEGIN rval = array_fill(NULL::jsonb, ARRAY[coalesce(jsonb_array_length(block->'events'), 0)]::integer[]); /** Note that arrays are 1-indexed in PostgreSQL and empty arrays return NULL for array_length. */ FOR i in 1..coalesce(array_length(rval, 1), 0) LOOP + event_start_time := clock_timestamp(); event_ = jsonb_array_element(block->'events', i-1); transaction_index = dydx_tendermint_event_to_transaction_index(event_); event_index = (event_->'eventIndex')::int; @@ -67,6 +72,16 @@ BEGIN ELSE NULL; END CASE; + + event_end_time := clock_timestamp(); + event_latency := event_end_time - event_start_time; + + -- Add the event latency in ms to the rval output for this event + rval[i] := jsonb_set( + rval[i], + '{latency}', + to_jsonb(EXTRACT(EPOCH FROM event_latency) * 1000) + ); END LOOP; RETURN rval; diff --git a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql index d6d1d4ee68..9c985c79ca 100644 --- a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql +++ b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql @@ -25,11 +25,16 @@ DECLARE event_index int; transaction_index int; event_data jsonb; + -- Latency tracking variables + event_start_time timestamp; + event_end_time timestamp; + event_latency interval; BEGIN rval = array_fill(NULL::jsonb, ARRAY[coalesce(jsonb_array_length(block->'events'), 0)]::integer[]); /** Note that arrays are 1-indexed in PostgreSQL and empty arrays return NULL for array_length. */ FOR i in 1..coalesce(array_length(rval, 1), 0) LOOP + event_start_time := clock_timestamp(); event_ = jsonb_array_element(block->'events', i-1); transaction_index = dydx_tendermint_event_to_transaction_index(event_); event_index = (event_->'eventIndex')::int; @@ -65,6 +70,16 @@ BEGIN ELSE NULL; END CASE; + + event_end_time := clock_timestamp(); + event_latency := event_end_time - event_start_time; + + -- Add the event latency in ms to the rval output for this event + rval[i] := jsonb_set( + rval[i], + '{latency}', + to_jsonb(EXTRACT(EPOCH FROM event_latency) * 1000) + ); END LOOP; RETURN rval; From 8b933c6de0668f0449adcf8bb0eed05d043fb85f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:02:10 -0400 Subject: [PATCH 008/120] Add oracle prices index on ("marketId", "effectiveAtHeight") (backport #2368) (#2374) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- ...rices_market_id_effective_at_height_index.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 indexer/packages/postgres/src/db/migrations/migration_files/20240926133526_create_oracle_prices_market_id_effective_at_height_index.ts diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20240926133526_create_oracle_prices_market_id_effective_at_height_index.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20240926133526_create_oracle_prices_market_id_effective_at_height_index.ts new file mode 100644 index 0000000000..8f80339ebf --- /dev/null +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20240926133526_create_oracle_prices_market_id_effective_at_height_index.ts @@ -0,0 +1,17 @@ +import * as Knex from 'knex'; + +export async function up(knex: Knex): Promise { + await knex.raw(` + CREATE INDEX CONCURRENTLY IF NOT EXISTS "oracle_prices_marketid_effectiveatheight_index" ON "oracle_prices" ("marketId", "effectiveAtHeight"); + `); +} + +export async function down(knex: Knex): Promise { + await knex.raw(` + DROP INDEX CONCURRENTLY IF EXISTS "oracle_prices_marketid_effectiveatheight_index"; + `); +} + +export const config = { + transaction: false, +}; From 0502f73833dab40b85c97dd23e62df858cd56125 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:39:19 -0400 Subject: [PATCH 009/120] Include getting main subaccount equity / pnl for megavault PnL query. (backport #2376) (#2378) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- indexer/packages/postgres/src/constants.ts | 5 ++ .../api/v4/vault-controller.test.ts | 66 ++++++++++++++++--- .../controllers/api/v4/vault-controller.ts | 27 ++++++-- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/indexer/packages/postgres/src/constants.ts b/indexer/packages/postgres/src/constants.ts index ac9a38e6cb..aa3dbc9bda 100644 --- a/indexer/packages/postgres/src/constants.ts +++ b/indexer/packages/postgres/src/constants.ts @@ -129,3 +129,8 @@ export const DEFAULT_POSTGRES_OPTIONS : Options = config.USE_READ_REPLICA export const MAX_PARENT_SUBACCOUNTS: number = 128; export const CHILD_SUBACCOUNT_MULTIPLIER: number = 1000; + +// From https://github.com/dydxprotocol/v4-chain/blob/protocol/v7.0.0-dev0/protocol/app/module_accounts_test.go#L41 +export const MEGAVAULT_MODULE_ADDRESS: string = 'dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r'; +// Generated from the module address + subaccount number 0. +export const MEGAVAULT_SUBACCOUNT_ID: string = 'c7169f81-0c80-54c5-a41f-9cbb6a538fdf'; 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 488435f8e7..e53a9b5b76 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 @@ -13,6 +13,8 @@ import { FundingIndexUpdatesTable, PnlTicksFromDatabase, VaultTable, + MEGAVAULT_MODULE_ADDRESS, + MEGAVAULT_SUBACCOUNT_ID, } from '@dydxprotocol-indexer/postgres'; import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; import request from 'supertest'; @@ -32,6 +34,7 @@ describe('vault-controller#V4', () => { const initialFundingIndex: string = '10000'; const vault1Equity: number = 159500; const vault2Equity: number = 10000; + const mainVaultEquity: number = 10000; beforeAll(async () => { await dbHelpers.migrate(); @@ -69,6 +72,12 @@ describe('vault-controller#V4', () => { }), ]); await SubaccountTable.create(testConstants.vaultSubaccount); + await SubaccountTable.create({ + address: MEGAVAULT_MODULE_ADDRESS, + subaccountNumber: 0, + updatedAt: latestTime.toISO(), + updatedAtHeight: latestBlockHeight, + }); await Promise.all([ PerpetualPositionTable.create( testConstants.defaultPerpetualPosition, @@ -146,7 +155,7 @@ describe('vault-controller#V4', () => { ['no resolution', '', [1, 2]], ['daily resolution', '?resolution=day', [1, 2]], ['hourly resolution', '?resolution=hour', [1, 2, 3]], - ])('Get /megavault/historicalPnl with 2 vault subaccounts (%s)', async ( + ])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async ( _name: string, queryParam: string, expectedTicksIndex: number[], @@ -162,22 +171,28 @@ describe('vault-controller#V4', () => { address: testConstants.vaultAddress, clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, }), + AssetPositionTable.upsert({ + ...testConstants.defaultAssetPosition, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + }), ]); - const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); + const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks( + true, // createMainSubaccounPnlTicks + ); const response: request.Response = await sendRequest({ type: RequestMethod.GET, path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`, }); const expectedPnlTickBase: any = { - equity: (parseFloat(testConstants.defaultPnlTick.equity) * 2).toString(), - totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 2).toString(), - netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 2).toString(), + equity: (parseFloat(testConstants.defaultPnlTick.equity) * 3).toString(), + totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 3).toString(), + netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 3).toString(), }; const finalTick: PnlTicksFromDatabase = { ...expectedPnlTickBase, - equity: Big(vault1Equity).add(vault2Equity).toFixed(), + equity: Big(vault1Equity).add(vault2Equity).add(mainVaultEquity).toFixed(), blockHeight: latestBlockHeight, blockTime: latestTime.toISO(), createdAt: latestTime.toISO(), @@ -449,8 +464,10 @@ describe('vault-controller#V4', () => { }); }); - async function createPnlTicks(): Promise { - return Promise.all([ + async function createPnlTicks( + createMainSubaccountPnlTicks: boolean = false, + ): Promise { + const createdTicks: PnlTicksFromDatabase[] = await Promise.all([ PnlTicksTable.create(testConstants.defaultPnlTick), PnlTicksTable.create({ ...testConstants.defaultPnlTick, @@ -496,5 +513,38 @@ describe('vault-controller#V4', () => { blockHeight: currentBlockHeight, }), ]); + + if (createMainSubaccountPnlTicks) { + const mainSubaccountTicks: PnlTicksFromDatabase[] = await Promise.all([ + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + blockTime: twoDaysAgo.toISO(), + createdAt: twoDaysAgo.toISO(), + blockHeight: twoDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + blockTime: twoHoursAgo.toISO(), + createdAt: twoHoursAgo.toISO(), + blockHeight: twoHourBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + blockTime: currentTime.toISO(), + createdAt: currentTime.toISO(), + blockHeight: currentBlockHeight, + }), + ]); + createdTicks.push(...mainSubaccountTicks); + } + + 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 e377f40c9b..6b967f3872 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -24,6 +24,7 @@ import { PnlTickInterval, VaultTable, VaultFromDatabase, + MEGAVAULT_SUBACCOUNT_ID, } from '@dydxprotocol-indexer/postgres'; import Big from 'big.js'; import express from 'express'; @@ -70,18 +71,24 @@ class VaultController extends Controller { @Query() resolution?: PnlTickInterval, ): Promise { const vaultSubaccounts: VaultMapping = await getVaultMapping(); + const vaultSubaccountIdsWithMainSubaccount: string[] = _ + .keys(vaultSubaccounts) + .concat([MEGAVAULT_SUBACCOUNT_ID]); const [ vaultPnlTicks, vaultPositions, latestBlock, + mainSubaccountEquity, ] : [ PnlTicksFromDatabase[], Map, BlockFromDatabase, + string, ] = await Promise.all([ - getVaultSubaccountPnlTicks(vaultSubaccounts, resolution), + getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, resolution), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), + getMainSubaccountEquity(), ]); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight @@ -92,7 +99,7 @@ class VaultController extends Controller { return position.equity; }).reduce((acc: string, curr: string): string => { return (Big(acc).add(Big(curr))).toFixed(); - }, '0'); + }, mainSubaccountEquity); const pnlTicksWithCurrentTick: PnlTicksFromDatabase[] = getPnlTicksWithCurrentTick( currentEquity, Array.from(aggregatedPnlTicks.values()), @@ -100,7 +107,7 @@ class VaultController extends Controller { ); return { - megavaultPnl: pnlTicksWithCurrentTick.map( + megavaultPnl: _.sortBy(pnlTicksWithCurrentTick, 'blockTime').map( (pnlTick: PnlTicksFromDatabase) => { return pnlTicksToResponseObject(pnlTick); }), @@ -121,7 +128,7 @@ class VaultController extends Controller { Map, BlockFromDatabase, ] = await Promise.all([ - getVaultSubaccountPnlTicks(vaultSubaccounts, resolution), + getVaultSubaccountPnlTicks(_.keys(vaultSubaccounts), resolution), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), ]); @@ -286,10 +293,9 @@ router.get( }); async function getVaultSubaccountPnlTicks( - vaultSubaccounts: VaultMapping, + vaultSubaccountIds: string[], resolution?: PnlTickInterval, ): Promise { - const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts); if (vaultSubaccountIds.length === 0) { return []; } @@ -437,6 +443,15 @@ async function getVaultPositions( )); } +async function getMainSubaccountEquity(): Promise { + // Main vault subaccount should only ever hold a USDC and never any perpetuals. + const usdcBalance: {[subaccountId: string]: Big} = await AssetPositionTable + .findUsdcPositionForSubaccounts( + [MEGAVAULT_SUBACCOUNT_ID], + ); + return usdcBalance[MEGAVAULT_SUBACCOUNT_ID]?.toFixed() || '0'; +} + function getPnlTicksWithCurrentTick( equity: string, pnlTicks: PnlTicksFromDatabase[], From 1389214a64d5ebc0207f02ba93604e38fccbcbd9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:25:05 -0400 Subject: [PATCH 010/120] Add function to fetch availability zone id (#2326) (backport #2390) (#2410) Co-authored-by: roy-dydx <133032749+roy-dydx@users.noreply.github.com> --- indexer/packages/base/package.json | 1 + indexer/packages/base/src/az-id.ts | 51 ++ indexer/packages/base/src/config.ts | 1 + indexer/packages/base/src/index.ts | 1 + indexer/pnpm-lock.yaml | 903 +++++++++++++++++++++++++++- 5 files changed, 955 insertions(+), 2 deletions(-) create mode 100644 indexer/packages/base/src/az-id.ts diff --git a/indexer/packages/base/package.json b/indexer/packages/base/package.json index b4c9e344eb..25219008df 100644 --- a/indexer/packages/base/package.json +++ b/indexer/packages/base/package.json @@ -32,6 +32,7 @@ }, "homepage": "https://github.com/dydxprotocol/indexer#readme", "dependencies": { + "@aws-sdk/client-ec2": "^3.354.0", "axios": "^1.2.1", "big.js": "^6.2.1", "bignumber.js": "^9.0.2", diff --git a/indexer/packages/base/src/az-id.ts b/indexer/packages/base/src/az-id.ts new file mode 100644 index 0000000000..d790c5f8cc --- /dev/null +++ b/indexer/packages/base/src/az-id.ts @@ -0,0 +1,51 @@ +import { DescribeAvailabilityZonesCommand, EC2Client } from '@aws-sdk/client-ec2'; + +import { axiosRequest } from './axios'; +import config from './config'; +import logger from './logger'; + +export async function getAvailabilityZoneId(): Promise { + if (config.ECS_CONTAINER_METADATA_URI_V4 !== '' && config.AWS_REGION !== '') { + const taskUrl = `${config.ECS_CONTAINER_METADATA_URI_V4}/task`; + try { + const response = await axiosRequest({ + method: 'GET', + url: taskUrl, + }) as { AvailabilityZone: string }; + const client = new EC2Client({ region: config.AWS_REGION }); + const command = new DescribeAvailabilityZonesCommand({ + ZoneNames: [response.AvailabilityZone], + }); + try { + const ec2Response = await client.send(command); + const zoneId = ec2Response.AvailabilityZones![0].ZoneId!; + logger.info({ + at: 'az-id#getAvailabilityZoneId', + message: `Got availability zone id ${zoneId}.`, + }); + return ec2Response.AvailabilityZones![0].ZoneId!; + } catch (error) { + logger.error({ + at: 'az-id#getAvailabilityZoneId', + message: 'Failed to fetch availabilty zone id from EC2. ', + error, + }); + return ''; + } + } catch (error) { + logger.error({ + at: 'az-id#getAvailabilityZoneId', + message: 'Failed to retrieve availability zone from metadata endpoint. No availabilty zone id found.', + error, + taskUrl, + }); + return ''; + } + } else { + logger.error({ + at: 'az-id#getAvailabilityZoneId', + message: 'No metadata URI or region. No availabilty zone id found.', + }); + return ''; + } +} diff --git a/indexer/packages/base/src/config.ts b/indexer/packages/base/src/config.ts index 1d88cc3284..4cee7802e7 100644 --- a/indexer/packages/base/src/config.ts +++ b/indexer/packages/base/src/config.ts @@ -39,6 +39,7 @@ export const baseConfigSchema = { STATSD_PORT: parseInteger({ default: 8125 }), LOG_LEVEL: parseString({ default: 'debug' }), ECS_CONTAINER_METADATA_URI_V4: parseString({ default: '' }), + AWS_REGION: parseString({ default: '' }), }; export default parseSchema(baseConfigSchema); diff --git a/indexer/packages/base/src/index.ts b/indexer/packages/base/src/index.ts index 5ec5dae958..77bbdf34e8 100644 --- a/indexer/packages/base/src/index.ts +++ b/indexer/packages/base/src/index.ts @@ -14,6 +14,7 @@ export * from './bugsnag'; export * from './stats-util'; export * from './date-helpers'; export * from './instance-id'; +export * from './az-id'; // Do this outside logger.ts to avoid a dependency cycle with logger transports that may trigger // additional logging. diff --git a/indexer/pnpm-lock.yaml b/indexer/pnpm-lock.yaml index 1ba4eae427..3f7362293d 100644 --- a/indexer/pnpm-lock.yaml +++ b/indexer/pnpm-lock.yaml @@ -13,6 +13,7 @@ importers: packages/base: specifiers: + '@aws-sdk/client-ec2': ^3.354.0 '@bugsnag/core': ^7.18.0 '@bugsnag/js': ^7.18.0 '@bugsnag/node': ^7.18.0 @@ -36,6 +37,7 @@ importers: winston: ^3.8.1 winston-transport: ^4.5.0 dependencies: + '@aws-sdk/client-ec2': 3.658.1 '@bugsnag/core': 7.18.0 '@bugsnag/js': 7.18.0 '@bugsnag/node': 7.18.0 @@ -888,6 +890,18 @@ packages: tslib: 1.14.1 dev: false + /@aws-crypto/sha256-browser/5.2.0: + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-locate-window': 3.310.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.7.0 + dev: false + /@aws-crypto/sha256-js/3.0.0: resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} dependencies: @@ -896,12 +910,27 @@ packages: tslib: 1.14.1 dev: false + /@aws-crypto/sha256-js/5.2.0: + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.654.0 + tslib: 2.7.0 + dev: false + /@aws-crypto/supports-web-crypto/3.0.0: resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} dependencies: tslib: 1.14.1 dev: false + /@aws-crypto/supports-web-crypto/5.2.0: + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + dependencies: + tslib: 2.7.0 + dev: false + /@aws-crypto/util/3.0.0: resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} dependencies: @@ -910,6 +939,14 @@ packages: tslib: 1.14.1 dev: false + /@aws-crypto/util/5.2.0: + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.7.0 + dev: false + /@aws-sdk/abort-controller/3.347.0: resolution: {integrity: sha512-P/2qE6ntYEmYG4Ez535nJWZbXqgbkJx8CMz7ChEuEg3Gp3dvVYEKg+iEUEvlqQ2U5dWP5J3ehw5po9t86IsVPQ==} engines: {node: '>=14.0.0'} @@ -918,6 +955,58 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/client-ec2/3.658.1: + resolution: {integrity: sha512-J/TdGg7Z8pwIL826QKwaX/EgND5Tst5N5hKcjwnj0jGfsJOkRTMdZTwOgvShYWgs6BplFFZqkl3t2dKsNfsVcg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.658.1_@aws-sdk+client-sts@3.658.1 + '@aws-sdk/client-sts': 3.658.1 + '@aws-sdk/core': 3.658.1 + '@aws-sdk/credential-provider-node': 3.658.1_48432e9e1d4872afb099a0b2260c0550 + '@aws-sdk/middleware-host-header': 3.654.0 + '@aws-sdk/middleware-logger': 3.654.0 + '@aws-sdk/middleware-recursion-detection': 3.654.0 + '@aws-sdk/middleware-sdk-ec2': 3.658.1 + '@aws-sdk/middleware-user-agent': 3.654.0 + '@aws-sdk/region-config-resolver': 3.654.0 + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-endpoints': 3.654.0 + '@aws-sdk/util-user-agent-browser': 3.654.0 + '@aws-sdk/util-user-agent-node': 3.654.0 + '@smithy/config-resolver': 3.0.8 + '@smithy/core': 2.4.6 + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/hash-node': 3.0.6 + '@smithy/invalid-dependency': 3.0.6 + '@smithy/middleware-content-length': 3.0.8 + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-retry': 3.0.21 + '@smithy/middleware-serde': 3.0.6 + '@smithy/middleware-stack': 3.0.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/node-http-handler': 3.2.3 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.21 + '@smithy/util-defaults-mode-node': 3.0.21 + '@smithy/util-endpoints': 2.1.2 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-retry': 3.0.6 + '@smithy/util-utf8': 3.0.0 + '@smithy/util-waiter': 3.1.5 + tslib: 2.7.0 + uuid: 9.0.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-ecr/3.354.0: resolution: {integrity: sha512-gy6cNm2y4TatqCoGkUspAgPfEGT2fsMIZGrfyPcx7cLsOiq+L5Wbs5AWFw6jywaRC88c6raUrpFLkPeVZjDZiQ==} engines: {node: '>=14.0.0'} @@ -1138,6 +1227,56 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.658.1_@aws-sdk+client-sts@3.658.1: + resolution: {integrity: sha512-RGcZAI3qEA05JszPKwa0cAyp8rnS1nUvs0Sqw4hqLNQ1kD7b7V6CPjRXe7EFQqCOMvM4kGqx0+cEEVTOmBsFLw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.658.1 + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.658.1 + '@aws-sdk/core': 3.658.1 + '@aws-sdk/credential-provider-node': 3.658.1_48432e9e1d4872afb099a0b2260c0550 + '@aws-sdk/middleware-host-header': 3.654.0 + '@aws-sdk/middleware-logger': 3.654.0 + '@aws-sdk/middleware-recursion-detection': 3.654.0 + '@aws-sdk/middleware-user-agent': 3.654.0 + '@aws-sdk/region-config-resolver': 3.654.0 + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-endpoints': 3.654.0 + '@aws-sdk/util-user-agent-browser': 3.654.0 + '@aws-sdk/util-user-agent-node': 3.654.0 + '@smithy/config-resolver': 3.0.8 + '@smithy/core': 2.4.6 + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/hash-node': 3.0.6 + '@smithy/invalid-dependency': 3.0.6 + '@smithy/middleware-content-length': 3.0.8 + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-retry': 3.0.21 + '@smithy/middleware-serde': 3.0.6 + '@smithy/middleware-stack': 3.0.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/node-http-handler': 3.2.3 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.21 + '@smithy/util-defaults-mode-node': 3.0.21 + '@smithy/util-endpoints': 2.1.2 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-retry': 3.0.6 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-sso/3.353.0: resolution: {integrity: sha512-/dP5jLvZYskk6eVxI/5uaC1AVEbE7B2yuQ+9O3Z9plPIlZXyZxzXHf06s4gwsS4hAc7TDs3DaB+AnfMVLOPHbQ==} engines: {node: '>=14.0.0'} @@ -1220,6 +1359,52 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso/3.658.1: + resolution: {integrity: sha512-lOuaBtqPTYGn6xpXlQF4LsNDsQ8Ij2kOdnk+i69Kp6yS76TYvtUuukyLL5kx8zE1c8WbYtxj9y8VNw9/6uKl7Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.658.1 + '@aws-sdk/middleware-host-header': 3.654.0 + '@aws-sdk/middleware-logger': 3.654.0 + '@aws-sdk/middleware-recursion-detection': 3.654.0 + '@aws-sdk/middleware-user-agent': 3.654.0 + '@aws-sdk/region-config-resolver': 3.654.0 + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-endpoints': 3.654.0 + '@aws-sdk/util-user-agent-browser': 3.654.0 + '@aws-sdk/util-user-agent-node': 3.654.0 + '@smithy/config-resolver': 3.0.8 + '@smithy/core': 2.4.6 + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/hash-node': 3.0.6 + '@smithy/invalid-dependency': 3.0.6 + '@smithy/middleware-content-length': 3.0.8 + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-retry': 3.0.21 + '@smithy/middleware-serde': 3.0.6 + '@smithy/middleware-stack': 3.0.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/node-http-handler': 3.2.3 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.21 + '@smithy/util-defaults-mode-node': 3.0.21 + '@smithy/util-endpoints': 2.1.2 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-retry': 3.0.6 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-sts/3.353.0: resolution: {integrity: sha512-jOnh242TtxG6st60AxLSav0MTgYlJn4c8ZDxk4Wk4+n5bypnXRrqgVXob99lyVnCRfP3OsDl1eilcVp94EXzVw==} engines: {node: '>=14.0.0'} @@ -1310,6 +1495,54 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sts/3.658.1: + resolution: {integrity: sha512-yw9hc5blTnbT1V6mR7Cx9HGc9KQpcLQ1QXj8rntiJi6tIYu3aFNVEyy81JHL7NsuBSeQulJTvHO3y6r3O0sfRg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.658.1_@aws-sdk+client-sts@3.658.1 + '@aws-sdk/core': 3.658.1 + '@aws-sdk/credential-provider-node': 3.658.1_48432e9e1d4872afb099a0b2260c0550 + '@aws-sdk/middleware-host-header': 3.654.0 + '@aws-sdk/middleware-logger': 3.654.0 + '@aws-sdk/middleware-recursion-detection': 3.654.0 + '@aws-sdk/middleware-user-agent': 3.654.0 + '@aws-sdk/region-config-resolver': 3.654.0 + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-endpoints': 3.654.0 + '@aws-sdk/util-user-agent-browser': 3.654.0 + '@aws-sdk/util-user-agent-node': 3.654.0 + '@smithy/config-resolver': 3.0.8 + '@smithy/core': 2.4.6 + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/hash-node': 3.0.6 + '@smithy/invalid-dependency': 3.0.6 + '@smithy/middleware-content-length': 3.0.8 + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-retry': 3.0.21 + '@smithy/middleware-serde': 3.0.6 + '@smithy/middleware-stack': 3.0.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/node-http-handler': 3.2.3 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.21 + '@smithy/util-defaults-mode-node': 3.0.21 + '@smithy/util-endpoints': 2.1.2 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-retry': 3.0.6 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/config-resolver/3.353.0: resolution: {integrity: sha512-rJJ1ebb8E4vfdGWym6jql1vodV+NUEATI1QqlwxQ0AZ8MGPIsT3uR52VyX7gp+yIrLZBJZdGYVNwrWSJgZ3B3w==} engines: {node: '>=14.0.0'} @@ -1330,6 +1563,22 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/core/3.658.1: + resolution: {integrity: sha512-vJVMoMcSKXK2gBRSu9Ywwv6wQ7tXH8VL1fqB1uVxgCqBZ3IHfqNn4zvpMPWrwgO2/3wv7XFyikGQ5ypPTCw4jA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/core': 2.4.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/property-provider': 3.1.6 + '@smithy/protocol-http': 4.1.3 + '@smithy/signature-v4': 4.1.4 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/util-middleware': 3.0.6 + fast-xml-parser: 4.4.1 + tslib: 2.7.0 + dev: false + /@aws-sdk/credential-provider-env/3.353.0: resolution: {integrity: sha512-Y4VsNS8O1FAD5J7S5itOhnOghQ5LIXlZ44t35nF8cbcF+JPvY3ToKzYpjYN1jM7DXKqU4shtqgYpzSqxlvEgKQ==} engines: {node: '>=14.0.0'} @@ -1339,6 +1588,31 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/credential-provider-env/3.654.0: + resolution: {integrity: sha512-kogsx3Ql81JouHS7DkheCDU9MYAvK0AokxjcshDveGmf7BbgbWCA8Fnb9wjQyNDaOXNvkZu8Z8rgkX91z324/w==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/property-provider': 3.1.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@aws-sdk/credential-provider-http/3.658.1: + resolution: {integrity: sha512-4ubkJjEVCZflxkZnV1JDQv8P2pburxk1LrEp55telfJRzXrnowzBKwuV2ED0QMNC448g2B3VCaffS+Ct7c4IWQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/node-http-handler': 3.2.3 + '@smithy/property-provider': 3.1.6 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/util-stream': 3.1.8 + tslib: 2.7.0 + dev: false + /@aws-sdk/credential-provider-imds/3.353.0: resolution: {integrity: sha512-n70yvXBN7E6NX7vA/wLTqyVayu/QKYsPvVn8Y+0A/j5oXXlVY+hQvjjEaNo0Zq1U8Z0L/kj3mutDpe57nTLKSg==} engines: {node: '>=14.0.0'} @@ -1395,6 +1669,29 @@ packages: - aws-crt dev: false + /@aws-sdk/credential-provider-ini/3.658.1_48432e9e1d4872afb099a0b2260c0550: + resolution: {integrity: sha512-2uwOamQg5ppwfegwen1ddPu5HM3/IBSnaGlaKLFhltkdtZ0jiqTZWUtX2V+4Q+buLnT0hQvLS/frQ+7QUam+0Q==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.658.1 + dependencies: + '@aws-sdk/client-sts': 3.658.1 + '@aws-sdk/credential-provider-env': 3.654.0 + '@aws-sdk/credential-provider-http': 3.658.1 + '@aws-sdk/credential-provider-process': 3.654.0 + '@aws-sdk/credential-provider-sso': 3.658.1_@aws-sdk+client-sso-oidc@3.658.1 + '@aws-sdk/credential-provider-web-identity': 3.654.0_@aws-sdk+client-sts@3.658.1 + '@aws-sdk/types': 3.654.0 + '@smithy/credential-provider-imds': 3.2.3 + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: false + /@aws-sdk/credential-provider-node/3.353.0: resolution: {integrity: sha512-OIyZ7OG1OQJ1aQGAu78hggSkK4jiWO1/Sm6wj5wvwylbST8NnR+dHjikZGFB3hoYt1uEe2O2LeGW67bI54VIEQ==} engines: {node: '>=14.0.0'} @@ -1431,6 +1728,28 @@ packages: - aws-crt dev: false + /@aws-sdk/credential-provider-node/3.658.1_48432e9e1d4872afb099a0b2260c0550: + resolution: {integrity: sha512-XwxW6N+uPXPYAuyq+GfOEdfL/MZGAlCSfB5gEWtLBFmFbikhmEuqfWtI6CD60OwudCUOh6argd21BsJf8o1SJA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.654.0 + '@aws-sdk/credential-provider-http': 3.658.1 + '@aws-sdk/credential-provider-ini': 3.658.1_48432e9e1d4872afb099a0b2260c0550 + '@aws-sdk/credential-provider-process': 3.654.0 + '@aws-sdk/credential-provider-sso': 3.658.1_@aws-sdk+client-sso-oidc@3.658.1 + '@aws-sdk/credential-provider-web-identity': 3.654.0_@aws-sdk+client-sts@3.658.1 + '@aws-sdk/types': 3.654.0 + '@smithy/credential-provider-imds': 3.2.3 + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/credential-provider-process/3.353.0: resolution: {integrity: sha512-IBkuxj3pCdmnTzIcRXhq+5sp1hsWACQLi9fHLK+mDEgaiaO+u2r3Th5tV3rJUfNhZY4qa62QNGsHwsVstVxGvw==} engines: {node: '>=14.0.0'} @@ -1451,6 +1770,17 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/credential-provider-process/3.654.0: + resolution: {integrity: sha512-PmQoo8sZ9Q2Ow8OMzK++Z9lI7MsRUG7sNq3E72DVA215dhtTICTDQwGlXH2AAmIp7n+G9LLRds+4wo2ehG4mkg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/credential-provider-sso/3.353.0: resolution: {integrity: sha512-S16tpQ7Zra2O3PNCV4a89wn8wVEgv8oRwjF7p87AM902fXEuag4VHIhaI/TgANQT737JDA/ZCFL2XSilCbHxYQ==} engines: {node: '>=14.0.0'} @@ -1479,6 +1809,22 @@ packages: - aws-crt dev: false + /@aws-sdk/credential-provider-sso/3.658.1_@aws-sdk+client-sso-oidc@3.658.1: + resolution: {integrity: sha512-YOagVEsZEk9DmgJEBg+4MBXrPcw/tYas0VQ5OVBqC5XHNbi2OBGJqgmjVPesuu393E7W0VQxtJFDS00O1ewQgA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.658.1 + '@aws-sdk/token-providers': 3.654.0_@aws-sdk+client-sso-oidc@3.658.1 + '@aws-sdk/types': 3.654.0 + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: false + /@aws-sdk/credential-provider-web-identity/3.353.0: resolution: {integrity: sha512-l3TdZB6tEDhLIl0oLIIy1njlxogpyIXSMW9fpuHBt7LDUwfBdCwVPE6+JpGXra6tJAfRQSv5l0lYx5osSLq98g==} engines: {node: '>=14.0.0'} @@ -1497,6 +1843,19 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/credential-provider-web-identity/3.654.0_@aws-sdk+client-sts@3.658.1: + resolution: {integrity: sha512-6a2g9gMtZToqSu+CusjNK5zvbLJahQ9di7buO3iXgbizXpLXU1rnawCpWxwslMpT5fLgMSKDnKDrr6wdEk7jSw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.654.0 + dependencies: + '@aws-sdk/client-sts': 3.658.1 + '@aws-sdk/types': 3.654.0 + '@smithy/property-provider': 3.1.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/eventstream-codec/3.347.0: resolution: {integrity: sha512-61q+SyspjsaQ4sdgjizMyRgVph2CiW4aAtfpoH69EJFJfTxTR/OqnZ9Jx/3YiYi0ksrvDenJddYodfWWJqD8/w==} dependencies: @@ -1604,6 +1963,16 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/middleware-host-header/3.654.0: + resolution: {integrity: sha512-rxGgVHWKp8U2ubMv+t+vlIk7QYUaRCHaVpmUlJv0Wv6Q0KeO9a42T9FxHphjOTlCGQOLcjCreL9CF8Qhtb4mdQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/middleware-logger/3.347.0: resolution: {integrity: sha512-NYC+Id5UCkVn+3P1t/YtmHt75uED06vwaKyxDy0UmB2K66PZLVtwWbLpVWrhbroaw1bvUHYcRyQ9NIfnVcXQjA==} engines: {node: '>=14.0.0'} @@ -1612,6 +1981,15 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/middleware-logger/3.654.0: + resolution: {integrity: sha512-OQYb+nWlmASyXfRb989pwkJ9EVUMP1CrKn2eyTk3usl20JZmKo2Vjis6I0tLUkMSxMhnBJJlQKyWkRpD/u1FVg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/middleware-recursion-detection/3.347.0: resolution: {integrity: sha512-qfnSvkFKCAMjMHR31NdsT0gv5Sq/ZHTUD4yQsSLpbVQ6iYAS834lrzXt41iyEHt57Y514uG7F/Xfvude3u4icQ==} engines: {node: '>=14.0.0'} @@ -1621,6 +1999,16 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/middleware-recursion-detection/3.654.0: + resolution: {integrity: sha512-gKSomgltKVmsT8sC6W7CrADZ4GHwX9epk3GcH6QhebVO3LA9LRbkL3TwOPUXakxxOLLUTYdOZLIOtFf7iH00lg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/middleware-retry/3.353.0: resolution: {integrity: sha512-v81NEzDGGvnpvFUy388razpicn7STwBA5gItlr3Ukz8ZWWudfQarTBr0nfVyODXb+76du2LwzEQOd6YtfoOZ+w==} engines: {node: '>=14.0.0'} @@ -1647,6 +2035,20 @@ packages: uuid: 8.3.2 dev: false + /@aws-sdk/middleware-sdk-ec2/3.658.1: + resolution: {integrity: sha512-CnkMajiLD8c+PyiqMjdRt3n87oZnd8jw+8mbtB0jX7Q9ED2z+oeG+RTZMXp2QEiZ0Q+7RyKjXf/PLRhARppFog==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-format-url': 3.654.0 + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/protocol-http': 4.1.3 + '@smithy/signature-v4': 4.1.4 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/middleware-sdk-sts/3.353.0: resolution: {integrity: sha512-GDpjznRBjvCvBfyLEhWb/FSmsnFR+nhBQC0N7d8pqWRqI084sy2ZRyQ6hNDWnImi6AvOabTBSfDm6cB5RexDow==} engines: {node: '>=14.0.0'} @@ -1714,6 +2116,17 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/middleware-user-agent/3.654.0: + resolution: {integrity: sha512-liCcqPAyRsr53cy2tYu4qeH4MMN0eh9g6k56XzI5xd4SghXH5YWh4qOYAlQ8T66ZV4nPMtD8GLtLXGzsH8moFg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@aws-sdk/util-endpoints': 3.654.0 + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/node-config-provider/3.353.0: resolution: {integrity: sha512-4j0dFHAIa0NwQOPZ/PgkyfCWRaaLhilGbL/cOHkndtUdV54WtG+9+21pKNtakfxncF0irtZvVOv/CW/5x909ZQ==} engines: {node: '>=14.0.0'} @@ -1778,6 +2191,18 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/region-config-resolver/3.654.0: + resolution: {integrity: sha512-ydGOrXJxj3x0sJhsXyTmvJVLAE0xxuTWFJihTl67RtaO7VRNtd82I3P3bwoMMaDn5WpmV5mPo8fEUDRlBm3fPg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/node-config-provider': 3.1.7 + '@smithy/types': 3.4.2 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.6 + tslib: 2.7.0 + dev: false + /@aws-sdk/service-error-classification/3.347.0: resolution: {integrity: sha512-xZ3MqSY81Oy2gh5g0fCtooAbahqh9VhsF8vcKjVX8+XPbGC8y+kej82+MsMg4gYL8gRFB9u4hgYbNgIS6JTAvg==} engines: {node: '>=14.0.0'} @@ -1862,6 +2287,20 @@ packages: - aws-crt dev: false + /@aws-sdk/token-providers/3.654.0_@aws-sdk+client-sso-oidc@3.658.1: + resolution: {integrity: sha512-D8GeJYmvbfWkQDtTB4owmIobSMexZel0fOoetwvgCQ/7L8VPph3Q2bn1TRRIXvH7wdt6DcDxA3tKMHPBkT3GlA==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.654.0 + dependencies: + '@aws-sdk/client-sso-oidc': 3.658.1_@aws-sdk+client-sts@3.658.1 + '@aws-sdk/types': 3.654.0 + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/types/3.347.0: resolution: {integrity: sha512-GkCMy79mdjU9OTIe5KT58fI/6uqdf8UmMdWqVHmFJ+UpEzOci7L/uw4sOXWo7xpPzLs6cJ7s5ouGZW4GRPmHFA==} engines: {node: '>=14.0.0'} @@ -1869,6 +2308,14 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/types/3.654.0: + resolution: {integrity: sha512-VWvbED3SV+10QJIcmU/PKjsKilsTV16d1I7/on4bvD/jo1qGeMXqLDBSen3ks/tuvXZF/mFc7ZW/W2DiLVtO7A==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/url-parser/3.347.0: resolution: {integrity: sha512-lhrnVjxdV7hl+yCnJfDZOaVLSqKjxN20MIOiijRiqaWGLGEAiSqBreMhL89X1WKCifxAs4zZf9YB9SbdziRpAA==} dependencies: @@ -1955,6 +2402,26 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/util-endpoints/3.654.0: + resolution: {integrity: sha512-i902fcBknHs0Irgdpi62+QMvzxE+bczvILXigYrlHL4+PiEnlMVpni5L5W1qCkNZXf8AaMrSBuR1NZAGp6UOUw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/types': 3.4.2 + '@smithy/util-endpoints': 2.1.2 + tslib: 2.7.0 + dev: false + + /@aws-sdk/util-format-url/3.654.0: + resolution: {integrity: sha512-2yAlJ/l1uTJhS52iu4+/EvdIyQhDBL+nATY8rEjFI0H+BHGVrJIH2CL4DByhvi2yvYwsqQX0HYah6pF/yoXukA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/querystring-builder': 3.0.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/util-hex-encoding/3.310.0: resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==} engines: {node: '>=14.0.0'} @@ -1966,7 +2433,7 @@ packages: resolution: {integrity: sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.7.0 dev: false /@aws-sdk/util-middleware/3.347.0: @@ -1999,6 +2466,15 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/util-user-agent-browser/3.654.0: + resolution: {integrity: sha512-ykYAJqvnxLt7wfrqya28wuH3/7NdrwzfiFd7NqEVQf7dXVxL5RPEpD7DxjcyQo3DsHvvdUvGZVaQhozycn1pzA==} + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/types': 3.4.2 + bowser: 2.11.0 + tslib: 2.7.0 + dev: false + /@aws-sdk/util-user-agent-node/3.353.0: resolution: {integrity: sha512-wAviGE0NFqGnaBi6JdjCjp/3DA4AprXQayg9fGphRmP6ncOHNHGonPj/60l+Itu+m78V2CbIS76jqCdUtyAZEQ==} engines: {node: '>=14.0.0'} @@ -2027,6 +2503,21 @@ packages: tslib: 2.5.0 dev: false + /@aws-sdk/util-user-agent-node/3.654.0: + resolution: {integrity: sha512-a0ojjdBN6pqv6gB4H/QPPSfhs7mFtlVwnmKCM/QrTaFzN0U810PJ1BST3lBx5sa23I5jWHGaoFY+5q65C3clLQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/types': 3.654.0 + '@smithy/node-config-provider': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@aws-sdk/util-utf8-browser/3.259.0: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} dependencies: @@ -5900,6 +6391,175 @@ packages: dependencies: '@sinonjs/commons': 1.8.3 + /@smithy/abort-controller/3.1.4: + resolution: {integrity: sha512-VupaALAQlXViW3/enTf/f5l5JZYSAxoJL7f0nanhNNKnww6DGCg1oYIuNP78KDugnkwthBO6iEcym16HhWV8RQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/config-resolver/3.0.8: + resolution: {integrity: sha512-Tv1obAC18XOd2OnDAjSWmmthzx6Pdeh63FbLin8MlPiuJ2ATpKkq0NcNOJFr0dO+JmZXnwu8FQxKJ3TKJ3Hulw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.7 + '@smithy/types': 3.4.2 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.6 + tslib: 2.7.0 + dev: false + + /@smithy/core/2.4.6: + resolution: {integrity: sha512-6lQQp99hnyuNNIzeTYSzCUXJHwvvFLY7hfdFGSJM95tjRDJGfzWYFRBXPaM9766LiiTsQ561KErtbufzUFSYUg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-retry': 3.0.21 + '@smithy/middleware-serde': 3.0.6 + '@smithy/protocol-http': 4.1.3 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/credential-provider-imds/3.2.3: + resolution: {integrity: sha512-VoxMzSzdvkkjMJNE38yQgx4CfnmT+Z+5EUXkg4x7yag93eQkVQgZvN3XBSHC/ylfBbLbAtdu7flTCChX9I+mVg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.7 + '@smithy/property-provider': 3.1.6 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + tslib: 2.7.0 + dev: false + + /@smithy/fetch-http-handler/3.2.8: + resolution: {integrity: sha512-Lqe0B8F5RM7zkw//6avq1SJ8AfaRd3ubFUS1eVp5WszV7p6Ne5hQ4dSuMHDpNRPhgTvj4va9Kd/pcVigHEHRow==} + dependencies: + '@smithy/protocol-http': 4.1.3 + '@smithy/querystring-builder': 3.0.6 + '@smithy/types': 3.4.2 + '@smithy/util-base64': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/hash-node/3.0.6: + resolution: {integrity: sha512-c/FHEdKK/7DU2z6ZE91L36ahyXWayR3B+FzELjnYq7wH5YqIseM24V+pWCS9kFn1Ln8OFGTf+pyYPiHZuX0s/Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/invalid-dependency/3.0.6: + resolution: {integrity: sha512-czM7Ioq3s8pIXht7oD+vmgy4Wfb4XavU/k/irO8NdXFFOx7YAlsCCcKOh/lJD1mJSYQqiR7NmpZ9JviryD/7AQ==} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/is-array-buffer/2.2.0: + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/is-array-buffer/3.0.0: + resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/middleware-content-length/3.0.8: + resolution: {integrity: sha512-VuyszlSO49WKh3H9/kIO2kf07VUwGV80QRiaDxUfP8P8UKlokz381ETJvwLhwuypBYhLymCYyNhB3fLAGBX2og==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/middleware-endpoint/3.1.3: + resolution: {integrity: sha512-KeM/OrK8MVFUsoJsmCN0MZMVPjKKLudn13xpgwIMpGTYpA8QZB2Xq5tJ+RE6iu3A6NhOI4VajDTwBsm8pwwrhg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-serde': 3.0.6 + '@smithy/node-config-provider': 3.1.7 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + '@smithy/url-parser': 3.0.6 + '@smithy/util-middleware': 3.0.6 + tslib: 2.7.0 + dev: false + + /@smithy/middleware-retry/3.0.21: + resolution: {integrity: sha512-/h0fElV95LekVVEJuSw+aI11S1Y3zIUwBc6h9ZbUv43Gl2weXsbQwjLoet6j/Qtb0phfrSxS6pNg6FqgJOWZkA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.7 + '@smithy/protocol-http': 4.1.3 + '@smithy/service-error-classification': 3.0.6 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-retry': 3.0.6 + tslib: 2.7.0 + uuid: 9.0.1 + dev: false + + /@smithy/middleware-serde/3.0.6: + resolution: {integrity: sha512-KKTUSl1MzOM0MAjGbudeaVNtIDo+PpekTBkCNwvfZlKndodrnvRo+00USatiyLOc0ujjO9UydMRu3O9dYML7ag==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/middleware-stack/3.0.6: + resolution: {integrity: sha512-2c0eSYhTQ8xQqHMcRxLMpadFbTXg6Zla5l0mwNftFCZMQmuhI7EbAJMx6R5eqfuV3YbJ3QGyS3d5uSmrHV8Khg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/node-config-provider/3.1.7: + resolution: {integrity: sha512-g3mfnC3Oo8pOI0dYuPXLtdW1WGVb3bR2tkV21GNkm0ZvQjLTtamXAwCWt/FCb0HGvKt3gHHmF1XerG0ICfalOg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/property-provider': 3.1.6 + '@smithy/shared-ini-file-loader': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/node-http-handler/3.2.3: + resolution: {integrity: sha512-/gcm5DJ3k1b1zEInzBGAZC8ntJ+jwrz1NcSIu+9dSXd1FfG0G6QgkDI40tt8/WYUbHtLyo8fEqtm2v29koWo/w==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/abort-controller': 3.1.4 + '@smithy/protocol-http': 4.1.3 + '@smithy/querystring-builder': 3.0.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/property-provider/3.1.6: + resolution: {integrity: sha512-NK3y/T7Q/Bw+Z8vsVs9MYIQ5v7gOX7clyrXcwhhIBQhbPgRl6JDrZbusO9qWDhcEus75Tg+VCxtIRfo3H76fpw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@smithy/protocol-http/1.0.1: resolution: {integrity: sha512-9OrEn0WfOVtBNYJUjUAn9AOiJ4lzERCJJ/JeZs8E6yajTGxBaFRxUnNBHiNqoDJVg076hY36UmEnPx7xXrvUSg==} engines: {node: '>=14.0.0'} @@ -5908,6 +6568,72 @@ packages: tslib: 2.5.0 dev: false + /@smithy/protocol-http/4.1.3: + resolution: {integrity: sha512-GcbMmOYpH9iRqtC05RbRnc/0FssxSTHlmaNhYBTgSgNCYpdR3Kt88u5GAZTBmouzv+Zlj/VRv92J9ruuDeJuEw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/querystring-builder/3.0.6: + resolution: {integrity: sha512-sQe08RunoObe+Usujn9+R2zrLuQERi3CWvRO3BvnoWSYUaIrLKuAIeY7cMeDax6xGyfIP3x/yFWbEKSXvOnvVg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + '@smithy/util-uri-escape': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/querystring-parser/3.0.6: + resolution: {integrity: sha512-UJKw4LlEkytzz2Wq+uIdHf6qOtFfee/o7ruH0jF5I6UAuU+19r9QV7nU3P/uI0l6+oElRHmG/5cBBcGJrD7Ozg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/service-error-classification/3.0.6: + resolution: {integrity: sha512-53SpchU3+DUZrN7J6sBx9tBiCVGzsib2e4sc512Q7K9fpC5zkJKs6Z9s+qbMxSYrkEkle6hnMtrts7XNkMJJMg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + dev: false + + /@smithy/shared-ini-file-loader/3.1.7: + resolution: {integrity: sha512-IA4K2qTJYXkF5OfVN4vsY1hfnUZjaslEE8Fsr/gGFza4TAC2A9NfnZuSY2srQIbt9bwtjHiAayrRVgKse4Q7fA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/signature-v4/4.1.4: + resolution: {integrity: sha512-72MiK7xYukNsnLJI9NqvUHqTu0ziEsfMsYNlWpiJfuGQnCTFKpckThlEatirvcA/LmT1h7rRO+pJD06PYsPu9Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/is-array-buffer': 3.0.0 + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-middleware': 3.0.6 + '@smithy/util-uri-escape': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/smithy-client/3.3.5: + resolution: {integrity: sha512-7IZi8J3Dr9n3tX+lcpmJ/5tCYIqoXdblFBaPuv0SEKZFRpCxE+TqIWL6I3t7jLlk9TWu3JSvEZAhtjB9yvB+zA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-endpoint': 3.1.3 + '@smithy/middleware-stack': 3.0.6 + '@smithy/protocol-http': 4.1.3 + '@smithy/types': 3.4.2 + '@smithy/util-stream': 3.1.8 + tslib: 2.7.0 + dev: false + /@smithy/types/1.0.0: resolution: {integrity: sha512-kc1m5wPBHQCTixwuaOh9vnak/iJm21DrSf9UK6yDE5S3mQQ4u11pqAUiKWnlrZnYkeLfAI9UEHj9OaMT1v5Umg==} engines: {node: '>=14.0.0'} @@ -5915,6 +6641,169 @@ packages: tslib: 2.5.0 dev: false + /@smithy/types/3.4.2: + resolution: {integrity: sha512-tHiFcfcVedVBHpmHUEUHOCCih8iZbIAYn9NvPsNzaPm/237I3imdDdZoOC8c87H5HBAVEa06tTgb+OcSWV9g5w==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/url-parser/3.0.6: + resolution: {integrity: sha512-47Op/NU8Opt49KyGpHtVdnmmJMsp2hEwBdyjuFB9M2V5QVOwA7pBhhxKN5z6ztKGrMw76gd8MlbPuzzvaAncuQ==} + dependencies: + '@smithy/querystring-parser': 3.0.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/util-base64/3.0.0: + resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-body-length-browser/3.0.0: + resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/util-body-length-node/3.0.0: + resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/util-buffer-from/2.2.0: + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-buffer-from/3.0.0: + resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/is-array-buffer': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-config-provider/3.0.0: + resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/util-defaults-mode-browser/3.0.21: + resolution: {integrity: sha512-M/FhTBk4c/SsB91dD/M4gMGfJO7z/qJaM9+XQQIqBOf4qzZYMExnP7R4VdGwxxH8IKMGW+8F0I4rNtVRrcfPoA==} + engines: {node: '>= 10.0.0'} + dependencies: + '@smithy/property-provider': 3.1.6 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + bowser: 2.11.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-defaults-mode-node/3.0.21: + resolution: {integrity: sha512-NiLinPvF86U3S2Pdx/ycqd4bnY5dmFSPNL5KYRwbNjqQFS09M5Wzqk8BNk61/47xCYz1X/6KeiSk9qgYPTtuDw==} + engines: {node: '>= 10.0.0'} + dependencies: + '@smithy/config-resolver': 3.0.8 + '@smithy/credential-provider-imds': 3.2.3 + '@smithy/node-config-provider': 3.1.7 + '@smithy/property-provider': 3.1.6 + '@smithy/smithy-client': 3.3.5 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/util-endpoints/2.1.2: + resolution: {integrity: sha512-FEISzffb4H8DLzGq1g4MuDpcv6CIG15fXoQzDH9SjpRJv6h7J++1STFWWinilG0tQh9H1v2UKWG19Jjr2B16zQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.7 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/util-hex-encoding/3.0.0: + resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/util-middleware/3.0.6: + resolution: {integrity: sha512-BxbX4aBhI1O9p87/xM+zWy0GzT3CEVcXFPBRDoHAM+pV0eSW156pR+PSYEz0DQHDMYDsYAflC2bQNz2uaDBUZQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/util-retry/3.0.6: + resolution: {integrity: sha512-BRZiuF7IwDntAbevqMco67an0Sr9oLQJqqRCsSPZZHYRnehS0LHDAkJk/pSmI7Z8c/1Vet294H7fY2fWUgB+Rg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/service-error-classification': 3.0.6 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + + /@smithy/util-stream/3.1.8: + resolution: {integrity: sha512-hoKOqSmb8FD3WLObuB5hwbM7bNIWgcnvkThokTvVq7J5PKjlLUK5qQQcB9zWLHIoSaIlf3VIv2OxZY2wtQjcRQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/fetch-http-handler': 3.2.8 + '@smithy/node-http-handler': 3.2.3 + '@smithy/types': 3.4.2 + '@smithy/util-base64': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-uri-escape/3.0.0: + resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.7.0 + dev: false + + /@smithy/util-utf8/2.3.0: + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-utf8/3.0.0: + resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/util-buffer-from': 3.0.0 + tslib: 2.7.0 + dev: false + + /@smithy/util-waiter/3.1.5: + resolution: {integrity: sha512-jYOSvM3H6sZe3CHjzD2VQNCjWBJs+4DbtwBMvUp9y5EnnwNa7NQxTeYeQw0CKCAdGGZ3QvVkyJmvbvs5M/B10A==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/abort-controller': 3.1.4 + '@smithy/types': 3.4.2 + tslib: 2.7.0 + dev: false + /@tootallnate/once/2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -9024,6 +9913,13 @@ packages: strnum: 1.0.5 dev: false + /fast-xml-parser/4.4.1: + resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fast-xml-parser/4.5.0: resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} hasBin: true @@ -14246,6 +15142,10 @@ packages: /tslib/2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + /tslib/2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + dev: false + /tsoa/5.1.1: resolution: {integrity: sha512-U6+5CyD3+u9Dtza0fBnv4+lgmbZEskYljzRpKf3edGCAGtMKD2rfjtDw9jUdTfWb1FEDvsnR3pRvsSGBXaOdsA==} engines: {node: '>=12.0.0', yarn: '>=1.9.4'} @@ -14523,7 +15423,6 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true dev: false - optional: true /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} From 6dc0501ce335c8df5fb3965305a920d6842b40ea Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:44:47 -0400 Subject: [PATCH 011/120] Create consumer using rack id (#2352) (backport #2393) (#2411) Co-authored-by: roy-dydx <133032749+roy-dydx@users.noreply.github.com> --- .../packages/kafka/__tests__/consumer.test.ts | 4 +- indexer/packages/kafka/src/consumer.ts | 75 +++++++++++-------- .../src/helpers/kafka/kafka-controller.ts | 6 +- indexer/services/scripts/src/print-block.ts | 6 +- .../src/helpers/kafka/kafka-controller.ts | 5 +- .../src/helpers/kafka/kafka-controller.ts | 6 +- 6 files changed, 56 insertions(+), 46 deletions(-) diff --git a/indexer/packages/kafka/__tests__/consumer.test.ts b/indexer/packages/kafka/__tests__/consumer.test.ts index de801b2dfe..e05d67d5e3 100644 --- a/indexer/packages/kafka/__tests__/consumer.test.ts +++ b/indexer/packages/kafka/__tests__/consumer.test.ts @@ -10,10 +10,10 @@ import { TO_ENDER_TOPIC } from '../src'; describe.skip('consumer', () => { beforeAll(async () => { await Promise.all([ - consumer.connect(), + consumer!.connect(), producer.connect(), ]); - await consumer.subscribe({ topic: TO_ENDER_TOPIC }); + await consumer!.subscribe({ topic: TO_ENDER_TOPIC }); await startConsumer(); }); diff --git a/indexer/packages/kafka/src/consumer.ts b/indexer/packages/kafka/src/consumer.ts index 93c41d12c5..82c26cf1e0 100644 --- a/indexer/packages/kafka/src/consumer.ts +++ b/indexer/packages/kafka/src/consumer.ts @@ -1,4 +1,5 @@ import { + getAvailabilityZoneId, logger, } from '@dydxprotocol-indexer/base'; import { @@ -13,15 +14,10 @@ const groupIdPrefix: string = config.SERVICE_NAME; const groupIdSuffix: string = config.KAFKA_ENABLE_UNIQUE_CONSUMER_GROUP_IDS ? `_${uuidv4()}` : ''; const groupId: string = `${groupIdPrefix}${groupIdSuffix}`; -export const consumer: Consumer = kafka.consumer({ - groupId, - sessionTimeout: config.KAFKA_SESSION_TIMEOUT_MS, - rebalanceTimeout: config.KAFKA_REBALANCE_TIMEOUT_MS, - heartbeatInterval: config.KAFKA_HEARTBEAT_INTERVAL_MS, - maxWaitTimeInMs: config.KAFKA_WAIT_MAX_TIME_MS, - readUncommitted: false, - maxBytes: 4194304, // 4MB -}); +// As a hack, we made this mutable since CommonJS doesn't support top level await. +// Top level await would needed to fetch the az id (used as rack id). +// eslint-disable-next-line import/no-mutable-exports +export let consumer: Consumer | undefined; // List of functions to run per message consumed. let onMessageFunction: (topic: string, message: KafkaMessage) => Promise; @@ -51,38 +47,51 @@ export function updateOnBatchFunction( // Whether the consumer is stopped. let stopped: boolean = false; -consumer.on('consumer.disconnect', async () => { +export async function stopConsumer(): Promise { logger.info({ - at: 'consumers#disconnect', - message: 'Kafka consumer disconnected', + at: 'kafka-consumer#stop', + message: 'Stopping kafka consumer', groupId, }); - if (!stopped) { - await consumer.connect(); - logger.info({ - at: 'kafka-consumer#disconnect', - message: 'Kafka consumer reconnected', - groupId, - }); - } else { + stopped = true; + await consumer!.disconnect(); +} + +export async function initConsumer(): Promise { + consumer = kafka.consumer({ + groupId, + sessionTimeout: config.KAFKA_SESSION_TIMEOUT_MS, + rebalanceTimeout: config.KAFKA_REBALANCE_TIMEOUT_MS, + heartbeatInterval: config.KAFKA_HEARTBEAT_INTERVAL_MS, + maxWaitTimeInMs: config.KAFKA_WAIT_MAX_TIME_MS, + readUncommitted: false, + maxBytes: 4194304, // 4MB + rackId: await getAvailabilityZoneId(), + }); + + consumer!.on('consumer.disconnect', async () => { logger.info({ - at: 'kafka-consumer#disconnect', - message: 'Not reconnecting since task is shutting down', + at: 'consumers#disconnect', + message: 'Kafka consumer disconnected', groupId, }); - } -}); -export async function stopConsumer(): Promise { - logger.info({ - at: 'kafka-consumer#stop', - message: 'Stopping kafka consumer', - groupId, + if (!stopped) { + await consumer!.connect(); + logger.info({ + at: 'kafka-consumer#disconnect', + message: 'Kafka consumer reconnected', + groupId, + }); + } else { + logger.info({ + at: 'kafka-consumer#disconnect', + message: 'Not reconnecting since task is shutting down', + groupId, + }); + } }); - - stopped = true; - await consumer.disconnect(); } export async function startConsumer(batchProcessing: boolean = false): Promise { @@ -104,7 +113,7 @@ export async function startConsumer(batchProcessing: boolean = false): Promise { await Promise.all([ - consumer.connect(), + initConsumer(), producer.connect(), ]); - await consumer.subscribe({ + await consumer!.subscribe({ topic: TO_ENDER_TOPIC, // https://kafka.js.org/docs/consuming#a-name-from-beginning-a-frombeginning // Need to set fromBeginning to true, so when ender restarts, it will consume all messages diff --git a/indexer/services/scripts/src/print-block.ts b/indexer/services/scripts/src/print-block.ts index 05855229ca..34d32a7728 100644 --- a/indexer/services/scripts/src/print-block.ts +++ b/indexer/services/scripts/src/print-block.ts @@ -42,7 +42,7 @@ export function seek(offset: bigint): void { offset: offset.toString(), }); - consumer.seek({ + consumer!.seek({ topic: TO_ENDER_TOPIC, partition: 0, offset: offset.toString(), @@ -57,11 +57,11 @@ export function seek(offset: bigint): void { export async function connect(height: number): Promise { await Promise.all([ - consumer.connect(), + consumer!.connect(), producer.connect(), ]); - await consumer.subscribe({ + await consumer!.subscribe({ topic: TO_ENDER_TOPIC, fromBeginning: true, }); diff --git a/indexer/services/socks/src/helpers/kafka/kafka-controller.ts b/indexer/services/socks/src/helpers/kafka/kafka-controller.ts index 03409f2849..247819f8bf 100644 --- a/indexer/services/socks/src/helpers/kafka/kafka-controller.ts +++ b/indexer/services/socks/src/helpers/kafka/kafka-controller.ts @@ -2,18 +2,19 @@ import { logger } from '@dydxprotocol-indexer/base'; import { WebsocketTopics, consumer, + initConsumer, stopConsumer, } from '@dydxprotocol-indexer/kafka'; export async function connect(): Promise { - await consumer.connect(); + await initConsumer(); logger.info({ at: 'kafka-controller#connect', message: 'Connected to Kafka', }); - await consumer.subscribe({ topics: Object.values(WebsocketTopics) }); + await consumer!.subscribe({ topics: Object.values(WebsocketTopics) }); } export async function disconnect(): Promise { diff --git a/indexer/services/vulcan/src/helpers/kafka/kafka-controller.ts b/indexer/services/vulcan/src/helpers/kafka/kafka-controller.ts index ae2038f0f3..528eb4b851 100644 --- a/indexer/services/vulcan/src/helpers/kafka/kafka-controller.ts +++ b/indexer/services/vulcan/src/helpers/kafka/kafka-controller.ts @@ -1,6 +1,6 @@ import { logger } from '@dydxprotocol-indexer/base'; import { - consumer, producer, KafkaTopics, updateOnMessageFunction, updateOnBatchFunction, + consumer, initConsumer, producer, KafkaTopics, updateOnMessageFunction, updateOnBatchFunction, } from '@dydxprotocol-indexer/kafka'; import { KafkaMessage } from 'kafkajs'; @@ -10,11 +10,11 @@ import { onMessage } from '../../lib/on-message'; export async function connect(): Promise { await Promise.all([ - consumer.connect(), + initConsumer(), producer.connect(), ]); - await consumer.subscribe({ + await consumer!.subscribe({ topic: KafkaTopics.TO_VULCAN, // https://kafka.js.org/docs/consuming#a-name-from-beginning-a-frombeginning // fromBeginning is by default set to false, so vulcan will only consume messages produced From 3e94eb45be82cabc4864dbeff7efdf55af413b8c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:48:18 -0400 Subject: [PATCH 012/120] Filter out to single tick per interval. (backport #2403) (#2418) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../api/v4/vault-controller.test.ts | 68 +++++++++++++---- indexer/services/comlink/src/config.ts | 1 + .../controllers/api/v4/vault-controller.ts | 75 ++++++++++++++++--- 3 files changed, 118 insertions(+), 26 deletions(-) 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 e53a9b5b76..72ae841616 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 @@ -24,13 +24,15 @@ import Big from 'big.js'; describe('vault-controller#V4', () => { const latestBlockHeight: string = '25'; - const currentBlockHeight: string = '7'; - const twoHourBlockHeight: string = '5'; + const currentBlockHeight: string = '9'; + const twoHourBlockHeight: string = '7'; + const almostTwoDayBlockHeight: string = '5'; const twoDayBlockHeight: string = '3'; const currentTime: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 }); const latestTime: DateTime = currentTime.plus({ second: 5 }); const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 }); const twoDaysAgo: DateTime = currentTime.minus({ day: 2 }); + const almostTwoDaysAgo: DateTime = currentTime.minus({ hour: 47 }); const initialFundingIndex: string = '10000'; const vault1Equity: number = 159500; const vault2Equity: number = 10000; @@ -70,6 +72,11 @@ describe('vault-controller#V4', () => { time: latestTime.toISO(), blockHeight: latestBlockHeight, }), + BlockTable.create({ + ...testConstants.defaultBlock, + time: almostTwoDaysAgo.toISO(), + blockHeight: almostTwoDayBlockHeight, + }), ]); await SubaccountTable.create(testConstants.vaultSubaccount); await SubaccountTable.create({ @@ -152,14 +159,27 @@ describe('vault-controller#V4', () => { }); it.each([ - ['no resolution', '', [1, 2]], - ['daily resolution', '?resolution=day', [1, 2]], - ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ['no resolution', '', [1, 2], [undefined, 6], [9, 10]], + ['daily resolution', '?resolution=day', [1, 2], [undefined, 6], [9, 10]], + [ + 'hourly resolution', + '?resolution=hour', + [1, undefined, 2, 3], + [undefined, 5, 6, 7], + [9, undefined, 10, 11], + ], ])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async ( _name: string, queryParam: string, - expectedTicksIndex: number[], + expectedTicksIndex1: (number | undefined)[], + expectedTicksIndex2: (number | undefined)[], + expectedTicksIndexMain: (number | undefined)[], ) => { + const expectedTicksArray: (number | undefined)[][] = [ + expectedTicksIndex1, + expectedTicksIndex2, + expectedTicksIndexMain, + ]; await Promise.all([ VaultTable.create({ ...testConstants.defaultVault, @@ -198,15 +218,33 @@ describe('vault-controller#V4', () => { createdAt: latestTime.toISO(), }; - expect(response.body.megavaultPnl).toHaveLength(expectedTicksIndex.length + 1); + expect(response.body.megavaultPnl).toHaveLength(expectedTicksIndex1.length + 1); expect(response.body.megavaultPnl).toEqual( expect.arrayContaining( - expectedTicksIndex.map((index: number) => { + expectedTicksIndex1.map((_: number | undefined, pos: number) => { + const pnlTickBase: any = { + equity: '0', + totalPnl: '0', + netTransfers: '0', + }; + let expectedTick: PnlTicksFromDatabase; + for (const expectedTicks of expectedTicksArray) { + if (expectedTicks[pos] !== undefined) { + expectedTick = createdPnlTicks[expectedTicks[pos]!]; + pnlTickBase.equity = Big(pnlTickBase.equity).add(expectedTick.equity).toFixed(); + pnlTickBase.totalPnl = Big(pnlTickBase.totalPnl) + .add(expectedTick.totalPnl) + .toFixed(); + pnlTickBase.netTransfers = Big(pnlTickBase.netTransfers) + .add(expectedTick.netTransfers) + .toFixed(); + } + } return expect.objectContaining({ - ...expectedPnlTickBase, - createdAt: createdPnlTicks[index].createdAt, - blockHeight: createdPnlTicks[index].blockHeight, - blockTime: createdPnlTicks[index].blockTime, + ...pnlTickBase, + createdAt: expectedTick!.createdAt, + blockHeight: expectedTick!.blockHeight, + blockTime: expectedTick!.blockTime, }); }).concat([expect.objectContaining(finalTick)]), ), @@ -494,9 +532,9 @@ describe('vault-controller#V4', () => { PnlTicksTable.create({ ...testConstants.defaultPnlTick, subaccountId: testConstants.vaultSubaccountId, - blockTime: twoDaysAgo.toISO(), - createdAt: twoDaysAgo.toISO(), - blockHeight: twoDayBlockHeight, + blockTime: almostTwoDaysAgo.toISO(), + createdAt: almostTwoDaysAgo.toISO(), + blockHeight: almostTwoDayBlockHeight, }), PnlTicksTable.create({ ...testConstants.defaultPnlTick, diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index 43d2c81222..1b70d73b4b 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -61,6 +61,7 @@ export const configSchema = { // Vaults config VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }), + VAULT_PNL_HISTORY_HOURS: parseInteger({ default: 72 }), }; //////////////////////////////////////////////////////////////////////////////// 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 6b967f3872..ee4a31fe64 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -30,6 +30,7 @@ import Big from 'big.js'; import express from 'express'; import { checkSchema, matchedData } from 'express-validator'; import _ from 'lodash'; +import { DateTime } from 'luxon'; import { Controller, Get, Query, Route, } from 'tsoa'; @@ -85,7 +86,7 @@ class VaultController extends Controller { BlockFromDatabase, string, ] = await Promise.all([ - getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, resolution), + getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, getResolution(resolution)), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), getMainSubaccountEquity(), @@ -102,7 +103,7 @@ class VaultController extends Controller { }, mainSubaccountEquity); const pnlTicksWithCurrentTick: PnlTicksFromDatabase[] = getPnlTicksWithCurrentTick( currentEquity, - Array.from(aggregatedPnlTicks.values()), + filterOutIntervalTicks(aggregatedPnlTicks, getResolution(resolution)), latestBlock, ); @@ -128,7 +129,7 @@ class VaultController extends Controller { Map, BlockFromDatabase, ] = await Promise.all([ - getVaultSubaccountPnlTicks(_.keys(vaultSubaccounts), resolution), + getVaultSubaccountPnlTicks(_.keys(vaultSubaccounts), getResolution(resolution)), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), ]); @@ -294,21 +295,22 @@ router.get( async function getVaultSubaccountPnlTicks( vaultSubaccountIds: string[], - resolution?: PnlTickInterval, + resolution: PnlTickInterval, ): Promise { if (vaultSubaccountIds.length === 0) { return []; } - let pnlTickInterval: PnlTickInterval; - if (resolution === undefined) { - pnlTickInterval = PnlTickInterval.day; + + let windowSeconds: number; + if (resolution === PnlTickInterval.day) { + windowSeconds = config.VAULT_PNL_HISTORY_DAYS * 24 * 60 * 60; // days to seconds } else { - pnlTickInterval = resolution; + windowSeconds = config.VAULT_PNL_HISTORY_HOURS * 60 * 60; // hours to seconds } const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( - pnlTickInterval, - config.VAULT_PNL_HISTORY_DAYS * 24 * 60 * 60, + resolution, + windowSeconds, vaultSubaccountIds, ); @@ -461,7 +463,7 @@ function getPnlTicksWithCurrentTick( return []; } const currentTick: PnlTicksFromDatabase = { - ...pnlTicks[pnlTicks.length - 1], + ...(_.maxBy(pnlTicks, 'blockTime')!), equity, blockHeight: latestBlock.blockHeight, blockTime: latestBlock.time, @@ -470,6 +472,57 @@ function getPnlTicksWithCurrentTick( return pnlTicks.concat([currentTick]); } +/** + * Takes in a map of block heights to PnlTicks and filters out the closest pnl tick per interval. + * @param pnlTicksByBlock Map of block number to pnl tick. + * @param resolution Resolution of interval. + * @returns Array of PnlTicksFromDatabase, one per interval. + */ +function filterOutIntervalTicks( + pnlTicksByBlock: Map, + resolution: PnlTickInterval, +): PnlTicksFromDatabase[] { + // Track block to block time. + const blockToBlockTime: Map = new Map(); + // Track start of days to closest block by block time. + const blocksPerInterval: Map = new Map(); + // Track start of days to closest Pnl tick. + const ticksPerInterval: Map = new Map(); + pnlTicksByBlock.forEach((pnlTick: PnlTicksFromDatabase, block: number): void => { + const blockTime: DateTime = DateTime.fromISO(pnlTick.blockTime).toUTC(); + blockToBlockTime.set(block, blockTime); + + const startOfInterval: DateTime = blockTime.toUTC().startOf(resolution); + const startOfIntervalStr: string = startOfInterval.toISO(); + const startOfIntervalBlock: number | undefined = blocksPerInterval.get(startOfIntervalStr); + // No block for the start of interval, set this block as the block for the interval. + if (startOfIntervalBlock === undefined) { + blocksPerInterval.set(startOfIntervalStr, block); + ticksPerInterval.set(startOfIntervalStr, pnlTick); + return; + } + + const startOfDayBlockTime: DateTime | undefined = blockToBlockTime.get(startOfIntervalBlock); + // Invalid block set as start of day block, set this block as the block for the day. + if (startOfDayBlockTime === undefined) { + blocksPerInterval.set(startOfIntervalStr, block); + ticksPerInterval.set(startOfIntervalStr, pnlTick); + return; + } + + // This block is closer to the start of the day, set it as the block for the day. + if (blockTime.diff(startOfInterval) < startOfDayBlockTime.diff(startOfInterval)) { + blocksPerInterval.set(startOfIntervalStr, block); + ticksPerInterval.set(startOfIntervalStr, pnlTick); + } + }); + return Array.from(ticksPerInterval.values()); +} + +function getResolution(resolution: PnlTickInterval = PnlTickInterval.day): PnlTickInterval { + return resolution; +} + async function getVaultMapping(): Promise { const vaults: VaultFromDatabase[] = await VaultTable.findAll( {}, From 6005a0d9c0267874937415455d59355ef0246faa Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:55:25 -0400 Subject: [PATCH 013/120] [CT-629] Fix entryPrice calc (backport #2415) (#2417) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- .../handlers/order-fills/liquidation-handler.test.ts | 4 ++-- .../__tests__/handlers/order-fills/order-handler.test.ts | 4 ++-- .../helpers/dydx_liquidation_fill_handler_per_order.sql | 2 +- .../dydx_update_perpetual_position_aggregate_fields.sql | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) 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 a5cc41f3d6..805ca676f0 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: '10', + size: '5', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -392,7 +392,7 @@ describe('LiquidationHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.sumOpen!).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 ba9a62ab34..1e2cdcb90b 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: '10', + size: '5', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -439,7 +439,7 @@ describe('OrderHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.sumOpen!).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 493b1257d6..4e1970c8d2 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", perpetual_position_record."sumOpen", + perpetual_position_record."entryPrice", perpetual_position_record."size", 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 d021eecf28..deda80b23f 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", perpetual_position_record."sumOpen", price, size + perpetual_position_record."entryPrice", perpetual_position_record."size", price, size ); perpetual_position_record."sumOpen" = sum_open; perpetual_position_record."entryPrice" = entry_price; From e8af710ce1bec39e10a491382242fa1c1eb8244e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:16:36 -0400 Subject: [PATCH 014/120] Revert "[CT-629] Fix entryPrice calc" (backport #2425) (#2426) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- .../handlers/order-fills/liquidation-handler.test.ts | 4 ++-- .../__tests__/handlers/order-fills/order-handler.test.ts | 4 ++-- .../helpers/dydx_liquidation_fill_handler_per_order.sql | 2 +- .../dydx_update_perpetual_position_aggregate_fields.sql | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) 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 1e2cdcb90b..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', @@ -439,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 4e1970c8d2..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", 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 deda80b23f..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", 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; From dbe13a34238d6536711fba5a2d53d3039f5359ba Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:37:03 -0400 Subject: [PATCH 015/120] Fix flaky vault test. (backport #2422) (#2424) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../__tests__/controllers/api/v4/vault-controller.test.ts | 5 +++++ 1 file changed, 5 insertions(+) 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 72ae841616..b2071c6681 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 @@ -21,6 +21,7 @@ import request from 'supertest'; import { getFixedRepresentation, sendRequest } from '../../../helpers/helpers'; import { DateTime } from 'luxon'; import Big from 'big.js'; +import config from '../../../../src/config'; describe('vault-controller#V4', () => { const latestBlockHeight: string = '25'; @@ -37,6 +38,7 @@ describe('vault-controller#V4', () => { const vault1Equity: number = 159500; const vault2Equity: number = 10000; const mainVaultEquity: number = 10000; + const vaultPnlHistoryHoursPrev: number = config.VAULT_PNL_HISTORY_HOURS; beforeAll(async () => { await dbHelpers.migrate(); @@ -48,6 +50,8 @@ describe('vault-controller#V4', () => { describe('GET /v1', () => { beforeEach(async () => { + // Get a week of data for hourly pnl ticks. + config.VAULT_PNL_HISTORY_HOURS = 168; await testMocks.seedData(); await perpetualMarketRefresher.updatePerpetualMarkets(); await liquidityTierRefresher.updateLiquidityTiers(); @@ -109,6 +113,7 @@ describe('vault-controller#V4', () => { afterEach(async () => { await dbHelpers.clearData(); + config.VAULT_PNL_HISTORY_HOURS = vaultPnlHistoryHoursPrev; }); it('Get /megavault/historicalPnl with no vault subaccounts', async () => { From 0b9e8a2c41f745f3963d583139e51b7c1586def1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:46:02 -0400 Subject: [PATCH 016/120] Split affiliate info fees by taker and maker (backport #2439) (#2448) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- .../postgres/__tests__/helpers/constants.ts | 15 +++++---- .../stores/affiliate-info-table.test.ts | 31 +++++++++++-------- ...44813_change_affiliate_info_fee_columns.ts | 25 +++++++++++++++ .../src/models/affiliate-info-model.ts | 25 +++++++++------ .../src/stores/affiliate-info-table.ts | 24 ++++++++------ .../src/types/affiliate-info-types.ts | 10 +++--- .../postgres/src/types/db-model-types.ts | 5 +-- .../api/v4/affiliates-controller.test.ts | 11 +++++-- .../comlink/public/api-documentation.md | 14 +++++++-- indexer/services/comlink/public/swagger.json | 12 ++++++- .../api/v4/affiliates-controller.ts | 11 +++++-- indexer/services/comlink/src/types.ts | 2 ++ .../tasks/update-affiliate-info.test.ts | 20 +++++++----- 13 files changed, 145 insertions(+), 60 deletions(-) create mode 100644 indexer/packages/postgres/src/db/migrations/migration_files/20241002144813_change_affiliate_info_fee_columns.ts diff --git a/indexer/packages/postgres/__tests__/helpers/constants.ts b/indexer/packages/postgres/__tests__/helpers/constants.ts index 56e2865227..5de24209bd 100644 --- a/indexer/packages/postgres/__tests__/helpers/constants.ts +++ b/indexer/packages/postgres/__tests__/helpers/constants.ts @@ -990,9 +990,10 @@ export const defaultAffiliateInfo: AffiliateInfoCreateObject = { affiliateEarnings: '10', referredMakerTrades: 10, referredTakerTrades: 20, - totalReferredFees: '10', + totalReferredMakerFees: '10', + totalReferredTakerFees: '10', + totalReferredMakerRebates: '-10', totalReferredUsers: 5, - referredNetProtocolEarnings: '20', firstReferralBlockHeight: '1', referredTotalVolume: '1000', }; @@ -1002,9 +1003,10 @@ export const defaultAffiliateInfo2: AffiliateInfoCreateObject = { affiliateEarnings: '11', referredMakerTrades: 11, referredTakerTrades: 21, - totalReferredFees: '11', + totalReferredMakerFees: '11', + totalReferredTakerFees: '11', + totalReferredMakerRebates: '-11', totalReferredUsers: 5, - referredNetProtocolEarnings: '21', firstReferralBlockHeight: '11', referredTotalVolume: '1000', }; @@ -1014,9 +1016,10 @@ export const defaultAffiliateInfo3: AffiliateInfoCreateObject = { affiliateEarnings: '12', referredMakerTrades: 12, referredTakerTrades: 22, - totalReferredFees: '12', + totalReferredMakerFees: '12', + totalReferredTakerFees: '12', + totalReferredMakerRebates: '-12', totalReferredUsers: 10, - referredNetProtocolEarnings: '22', firstReferralBlockHeight: '12', referredTotalVolume: '1111111', }; diff --git a/indexer/packages/postgres/__tests__/stores/affiliate-info-table.test.ts b/indexer/packages/postgres/__tests__/stores/affiliate-info-table.test.ts index 04790001c8..9c9eddc6eb 100644 --- a/indexer/packages/postgres/__tests__/stores/affiliate-info-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/affiliate-info-table.test.ts @@ -113,9 +113,10 @@ describe('Affiliate info store', () => { affiliateEarnings: '1000', referredMakerTrades: 1, referredTakerTrades: 1, - totalReferredFees: '2000', + totalReferredMakerFees: '0', + totalReferredTakerFees: '1000', + totalReferredMakerRebates: '-1000', totalReferredUsers: 1, - referredNetProtocolEarnings: '1000', firstReferralBlockHeight: '1', referredTotalVolume: '2', }; @@ -140,9 +141,10 @@ describe('Affiliate info store', () => { affiliateEarnings: '1000', referredMakerTrades: 2, referredTakerTrades: 0, - totalReferredFees: '2000', + totalReferredMakerFees: '2000', + totalReferredTakerFees: '0', + totalReferredMakerRebates: '0', totalReferredUsers: 1, - referredNetProtocolEarnings: '1000', firstReferralBlockHeight: '1', referredTotalVolume: '2', }; @@ -157,14 +159,15 @@ describe('Affiliate info store', () => { const updatedInfo2 = await AffiliateInfoTable.findById( defaultWallet2.address, ); - const expectedAffiliateInfo2 = { + const expectedAffiliateInfo2: AffiliateInfoFromDatabase = { address: defaultWallet2.address, affiliateEarnings: '2000', referredMakerTrades: 3, referredTakerTrades: 1, - totalReferredFees: '4000', + totalReferredMakerFees: '2000', + totalReferredTakerFees: '1000', + totalReferredMakerRebates: '-1000', totalReferredUsers: 1, - referredNetProtocolEarnings: '2000', firstReferralBlockHeight: '1', referredTotalVolume: '4', }; @@ -183,14 +186,15 @@ describe('Affiliate info store', () => { const updatedInfo3 = await AffiliateInfoTable.findById( defaultWallet2.address, ); - const expectedAffiliateInfo3 = { + const expectedAffiliateInfo3: AffiliateInfoFromDatabase = { address: defaultWallet2.address, affiliateEarnings: '2000', referredMakerTrades: 3, referredTakerTrades: 1, - totalReferredFees: '4000', + totalReferredMakerFees: '2000', + totalReferredTakerFees: '1000', + totalReferredMakerRebates: '-1000', totalReferredUsers: 2, - referredNetProtocolEarnings: '2000', firstReferralBlockHeight: '1', referredTotalVolume: '4', }; @@ -236,9 +240,10 @@ describe('Affiliate info store', () => { affiliateEarnings: '0', referredMakerTrades: 0, referredTakerTrades: 0, - totalReferredFees: '0', + totalReferredMakerFees: '0', + totalReferredTakerFees: '0', + totalReferredMakerRebates: '0', totalReferredUsers: 1, - referredNetProtocolEarnings: '0', firstReferralBlockHeight: '2', referredTotalVolume: '0', }; @@ -391,7 +396,7 @@ async function populateFillsAndReferrals(): Promise { eventId: defaultTendermintEventId2, price: '1', size: '1', - fee: '1000', + fee: '-1000', affiliateRevShare: '500', }), FillTable.create({ diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20241002144813_change_affiliate_info_fee_columns.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20241002144813_change_affiliate_info_fee_columns.ts new file mode 100644 index 0000000000..877b2524c0 --- /dev/null +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20241002144813_change_affiliate_info_fee_columns.ts @@ -0,0 +1,25 @@ +import * as Knex from 'knex'; + +export async function up(knex: Knex): Promise { + return knex + .schema + .alterTable('affiliate_info', (table) => { + table.dropColumn('totalReferredFees'); + table.dropColumn('referredNetProtocolEarnings'); + table.decimal('totalReferredTakerFees', null).notNullable().defaultTo(0); + table.decimal('totalReferredMakerFees', null).notNullable().defaultTo(0); + table.decimal('totalReferredMakerRebates', null).notNullable().defaultTo(0); + }); +} + +export async function down(knex: Knex): Promise { + return knex + .schema + .alterTable('affiliate_info', (table) => { + table.decimal('totalReferredFees', null).notNullable().defaultTo(0); + table.decimal('referredNetProtocolEarnings', null).notNullable().defaultTo(0); + table.dropColumn('totalReferredTakerFees'); + table.dropColumn('totalReferredMakerFees'); + table.dropColumn('totalReferredMakerRebates'); + }); +} diff --git a/indexer/packages/postgres/src/models/affiliate-info-model.ts b/indexer/packages/postgres/src/models/affiliate-info-model.ts index 7fcbefac39..49dd0dfdbd 100644 --- a/indexer/packages/postgres/src/models/affiliate-info-model.ts +++ b/indexer/packages/postgres/src/models/affiliate-info-model.ts @@ -1,4 +1,4 @@ -import { NonNegativeNumericPattern } from '../lib/validators'; +import { NonNegativeNumericPattern, NumericPattern } from '../lib/validators'; import UpsertQueryBuilder from '../query-builders/upsert'; import BaseModel from './base-model'; @@ -19,9 +19,10 @@ export default class AffiliateInfoModel extends BaseModel { 'affiliateEarnings', 'referredMakerTrades', 'referredTakerTrades', - 'totalReferredFees', + 'totalReferredMakerFees', + 'totalReferredTakerFees', + 'totalReferredMakerRebates', 'totalReferredUsers', - 'referredNetProtocolEarnings', 'firstReferralBlockHeight', 'referredTotalVolume', ], @@ -30,9 +31,10 @@ export default class AffiliateInfoModel extends BaseModel { affiliateEarnings: { type: 'string', pattern: NonNegativeNumericPattern }, referredMakerTrades: { type: 'int' }, referredTakerTrades: { type: 'int' }, - totalReferredFees: { type: 'string', pattern: NonNegativeNumericPattern }, + totalReferredMakerFees: { type: 'string', pattern: NonNegativeNumericPattern }, + totalReferredTakerFees: { type: 'string', pattern: NonNegativeNumericPattern }, + totalReferredMakerRebates: { type: 'string', pattern: NumericPattern }, totalReferredUsers: { type: 'int' }, - referredNetProtocolEarnings: { type: 'string', pattern: NonNegativeNumericPattern }, firstReferralBlockHeight: { type: 'string', pattern: NonNegativeNumericPattern }, referredTotalVolume: { type: 'string', pattern: NonNegativeNumericPattern }, }, @@ -51,9 +53,10 @@ export default class AffiliateInfoModel extends BaseModel { affiliateEarnings: 'string', referredMakerTrades: 'int', referredTakerTrades: 'int', - totalReferredFees: 'string', + totalReferredMakerFees: 'string', + totalReferredTakerFees: 'string', + totalReferredMakerRebates: 'string', totalReferredUsers: 'int', - referredNetProtocolEarnings: 'string', firstReferralBlockHeight: 'string', referredTotalVolume: 'string', }; @@ -69,11 +72,13 @@ export default class AffiliateInfoModel extends BaseModel { referredTakerTrades!: number; - totalReferredFees!: string; + totalReferredMakerFees!: string; - totalReferredUsers!: number; + totalReferredTakerFees!: string; + + totalReferredMakerRebates!: string; - referredNetProtocolEarnings!: string; + totalReferredUsers!: number; firstReferralBlockHeight!: string; diff --git a/indexer/packages/postgres/src/stores/affiliate-info-table.ts b/indexer/packages/postgres/src/stores/affiliate-info-table.ts index 6c2ab2adc4..d661a01d70 100644 --- a/indexer/packages/postgres/src/stores/affiliate-info-table.ts +++ b/indexer/packages/postgres/src/stores/affiliate-info-table.ts @@ -192,7 +192,9 @@ affiliate_stats AS ( affiliate_fills."affiliateAddress", SUM(affiliate_fills."fee") AS "totalReferredFees", SUM(affiliate_fills."affiliateRevShare") AS "affiliateEarnings", - SUM(affiliate_fills."fee") - SUM(affiliate_fills."affiliateRevShare") AS "referredNetProtocolEarnings", + SUM(CASE WHEN affiliate_fills."liquidity" = '${Liquidity.MAKER}' AND affiliate_fills."fee" > 0 THEN affiliate_fills."fee" ELSE 0 END) AS "totalReferredMakerFees", + SUM(CASE WHEN affiliate_fills."liquidity" = '${Liquidity.TAKER}' THEN affiliate_fills."fee" ELSE 0 END) AS "totalReferredTakerFees", + SUM(CASE WHEN affiliate_fills."liquidity" = '${Liquidity.MAKER}' AND affiliate_fills."fee" < 0 THEN affiliate_fills."fee" ELSE 0 END) AS "totalReferredMakerRebates", COUNT(CASE WHEN affiliate_fills."liquidity" = '${Liquidity.MAKER}' THEN 1 END) AS "referredMakerTrades", COUNT(CASE WHEN affiliate_fills."liquidity" = '${Liquidity.TAKER}' THEN 1 END) AS "referredTakerTrades", SUM(affiliate_fills."price" * affiliate_fills."size") AS "referredTotalVolume" @@ -210,9 +212,10 @@ affiliate_info_update AS ( affiliate_metadata."affiliateAddress", affiliate_metadata."totalReferredUsers", affiliate_metadata."firstReferralBlockHeight", - COALESCE(affiliate_stats."totalReferredFees", 0) AS "totalReferredFees", + COALESCE(affiliate_stats."totalReferredMakerFees", 0) AS "totalReferredMakerFees", + COALESCE(affiliate_stats."totalReferredTakerFees", 0) AS "totalReferredTakerFees", + COALESCE(affiliate_stats."totalReferredMakerRebates", 0) AS "totalReferredMakerRebates", COALESCE(affiliate_stats."affiliateEarnings", 0) AS "affiliateEarnings", - COALESCE(affiliate_stats."referredNetProtocolEarnings", 0) AS "referredNetProtocolEarnings", COALESCE(affiliate_stats."referredMakerTrades", 0) AS "referredMakerTrades", COALESCE(affiliate_stats."referredTakerTrades", 0) AS "referredTakerTrades", COALESCE(affiliate_stats."referredTotalVolume", 0) AS "referredTotalVolume" @@ -231,8 +234,9 @@ INSERT INTO affiliate_info ( "affiliateEarnings", "referredMakerTrades", "referredTakerTrades", - "totalReferredFees", - "referredNetProtocolEarnings", + "totalReferredMakerFees", + "totalReferredTakerFees", + "totalReferredMakerRebates", "referredTotalVolume" ) SELECT @@ -242,8 +246,9 @@ SELECT "affiliateEarnings", "referredMakerTrades", "referredTakerTrades", - "totalReferredFees", - "referredNetProtocolEarnings", + "totalReferredMakerFees", + "totalReferredTakerFees", + "totalReferredMakerRebates", "referredTotalVolume" FROM affiliate_info_update @@ -254,8 +259,9 @@ DO UPDATE SET "affiliateEarnings" = affiliate_info."affiliateEarnings" + EXCLUDED."affiliateEarnings", "referredMakerTrades" = affiliate_info."referredMakerTrades" + EXCLUDED."referredMakerTrades", "referredTakerTrades" = affiliate_info."referredTakerTrades" + EXCLUDED."referredTakerTrades", - "totalReferredFees" = affiliate_info."totalReferredFees" + EXCLUDED."totalReferredFees", - "referredNetProtocolEarnings" = affiliate_info."referredNetProtocolEarnings" + EXCLUDED."referredNetProtocolEarnings", + "totalReferredMakerFees" = affiliate_info."totalReferredMakerFees" + EXCLUDED."totalReferredMakerFees", + "totalReferredTakerFees" = affiliate_info."totalReferredTakerFees" + EXCLUDED."totalReferredTakerFees", + "totalReferredMakerRebates" = affiliate_info."totalReferredMakerRebates" + EXCLUDED."totalReferredMakerRebates", "referredTotalVolume" = affiliate_info."referredTotalVolume" + EXCLUDED."referredTotalVolume"; `; diff --git a/indexer/packages/postgres/src/types/affiliate-info-types.ts b/indexer/packages/postgres/src/types/affiliate-info-types.ts index 885de8b9b7..a1dcc61be6 100644 --- a/indexer/packages/postgres/src/types/affiliate-info-types.ts +++ b/indexer/packages/postgres/src/types/affiliate-info-types.ts @@ -3,9 +3,10 @@ export interface AffiliateInfoCreateObject { affiliateEarnings: string, referredMakerTrades: number, referredTakerTrades: number, - totalReferredFees: string, + totalReferredMakerFees: string, + totalReferredTakerFees: string, + totalReferredMakerRebates: string, totalReferredUsers: number, - referredNetProtocolEarnings: string, firstReferralBlockHeight: string, referredTotalVolume: string, } @@ -15,9 +16,10 @@ export enum AffiliateInfoColumns { affiliateEarnings = 'affiliateEarnings', referredMakerTrades = 'referredMakerTrades', referredTakerTrades = 'referredTakerTrades', - totalReferredFees = 'totalReferredFees', + totalReferredMakerFees = 'totalReferredMakerFees', + totalReferredTakerFees = 'totalReferredTakerFees', + totalReferredMakerRebates = 'totalReferredMakerRebates', totalReferredUsers = 'totalReferredUsers', - referredNetProtocolEarnings = 'referredNetProtocolEarnings', firstReferralBlockHeight = 'firstReferralBlockHeight', referredTotalVolume = 'referredTotalVolume', } diff --git a/indexer/packages/postgres/src/types/db-model-types.ts b/indexer/packages/postgres/src/types/db-model-types.ts index b400153118..9557be8ede 100644 --- a/indexer/packages/postgres/src/types/db-model-types.ts +++ b/indexer/packages/postgres/src/types/db-model-types.ts @@ -288,9 +288,10 @@ export interface AffiliateInfoFromDatabase { affiliateEarnings: string, referredMakerTrades: number, referredTakerTrades: number, - totalReferredFees: string, + totalReferredMakerFees: string, + totalReferredTakerFees: string, + totalReferredMakerRebates: string, totalReferredUsers: number, - referredNetProtocolEarnings: string, firstReferralBlockHeight: string, referredTotalVolume: string, } diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts index ea89899e15..30ceebd062 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts @@ -369,9 +369,16 @@ function affiliateInfoCreateToResponseObject( affiliateEarnings: Number(info.affiliateEarnings), affiliateReferredTrades: Number(info.referredTakerTrades) + Number(info.referredMakerTrades), - affiliateTotalReferredFees: Number(info.totalReferredFees), + affiliateTotalReferredFees: Number(info.totalReferredMakerFees) + + Number(info.totalReferredTakerFees) + + Number(info.totalReferredMakerRebates), affiliateReferredUsers: Number(info.totalReferredUsers), - affiliateReferredNetProtocolEarnings: Number(info.referredNetProtocolEarnings), + affiliateReferredNetProtocolEarnings: Number(info.totalReferredMakerFees) + + Number(info.totalReferredTakerFees) + + Number(info.totalReferredMakerRebates) - + Number(info.affiliateEarnings), affiliateReferredTotalVolume: Number(info.referredTotalVolume), + affiliateReferredMakerFees: Number(info.totalReferredMakerFees), + affiliateReferredTakerFees: Number(info.totalReferredTakerFees), }; } diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index 4d08bf1430..eaec0a2fbe 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -653,7 +653,9 @@ fetch(`${baseURL}/affiliates/snapshot`, "affiliateTotalReferredFees": 0.1, "affiliateReferredUsers": 0.1, "affiliateReferredNetProtocolEarnings": 0.1, - "affiliateReferredTotalVolume": 0.1 + "affiliateReferredTotalVolume": 0.1, + "affiliateReferredMakerFees": 0.1, + "affiliateReferredTakerFees": 0.1 } ], "total": 0.1, @@ -4244,7 +4246,9 @@ This operation does not require authentication "affiliateTotalReferredFees": 0.1, "affiliateReferredUsers": 0.1, "affiliateReferredNetProtocolEarnings": 0.1, - "affiliateReferredTotalVolume": 0.1 + "affiliateReferredTotalVolume": 0.1, + "affiliateReferredMakerFees": 0.1, + "affiliateReferredTakerFees": 0.1 } ``` @@ -4261,6 +4265,8 @@ This operation does not require authentication |affiliateReferredUsers|number(double)|true|none|none| |affiliateReferredNetProtocolEarnings|number(double)|true|none|none| |affiliateReferredTotalVolume|number(double)|true|none|none| +|affiliateReferredMakerFees|number(double)|true|none|none| +|affiliateReferredTakerFees|number(double)|true|none|none| ## AffiliateSnapshotResponse @@ -4280,7 +4286,9 @@ This operation does not require authentication "affiliateTotalReferredFees": 0.1, "affiliateReferredUsers": 0.1, "affiliateReferredNetProtocolEarnings": 0.1, - "affiliateReferredTotalVolume": 0.1 + "affiliateReferredTotalVolume": 0.1, + "affiliateReferredMakerFees": 0.1, + "affiliateReferredTakerFees": 0.1 } ], "total": 0.1, diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 23de12c60c..e94a095d65 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -303,6 +303,14 @@ "affiliateReferredTotalVolume": { "type": "number", "format": "double" + }, + "affiliateReferredMakerFees": { + "type": "number", + "format": "double" + }, + "affiliateReferredTakerFees": { + "type": "number", + "format": "double" } }, "required": [ @@ -313,7 +321,9 @@ "affiliateTotalReferredFees", "affiliateReferredUsers", "affiliateReferredNetProtocolEarnings", - "affiliateReferredTotalVolume" + "affiliateReferredTotalVolume", + "affiliateReferredMakerFees", + "affiliateReferredTakerFees" ], "type": "object", "additionalProperties": false diff --git a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts index 76e2433255..ac246bbfdf 100644 --- a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts @@ -164,10 +164,17 @@ class AffiliatesController extends Controller { info.address in addressUsernameMap ? addressUsernameMap[info.address] : '', affiliateEarnings: Number(info.affiliateEarnings), affiliateReferredTrades: Number(info.referredMakerTrades) + Number(info.referredTakerTrades), - affiliateTotalReferredFees: Number(info.totalReferredFees), + affiliateTotalReferredFees: Number(info.totalReferredMakerFees) + + Number(info.totalReferredTakerFees) + + Number(info.totalReferredMakerRebates), affiliateReferredUsers: Number(info.totalReferredUsers), - affiliateReferredNetProtocolEarnings: Number(info.referredNetProtocolEarnings), + affiliateReferredNetProtocolEarnings: Number(info.totalReferredMakerFees) + + Number(info.totalReferredTakerFees) + + Number(info.totalReferredMakerRebates) - + Number(info.affiliateEarnings), affiliateReferredTotalVolume: Number(info.referredTotalVolume), + affiliateReferredMakerFees: Number(info.totalReferredMakerFees), + affiliateReferredTakerFees: Number(info.totalReferredTakerFees), })); const response: AffiliateSnapshotResponse = { diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index c777521f48..81eace3303 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -731,6 +731,8 @@ export interface AffiliateSnapshotResponseObject { affiliateReferredUsers: number, affiliateReferredNetProtocolEarnings: number, affiliateReferredTotalVolume: number, + affiliateReferredMakerFees: number, + affiliateReferredTakerFees: number, } export interface AffiliateTotalVolumeResponse { diff --git a/indexer/services/roundtable/__tests__/tasks/update-affiliate-info.test.ts b/indexer/services/roundtable/__tests__/tasks/update-affiliate-info.test.ts index adc63c68e3..26b139cdb8 100644 --- a/indexer/services/roundtable/__tests__/tasks/update-affiliate-info.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/update-affiliate-info.test.ts @@ -72,9 +72,10 @@ describe('update-affiliate-info', () => { affiliateEarnings: '0', referredMakerTrades: 0, referredTakerTrades: 0, - totalReferredFees: '0', + totalReferredMakerFees: '0', + totalReferredTakerFees: '0', + totalReferredMakerRebates: '0', totalReferredUsers: 1, - referredNetProtocolEarnings: '0', firstReferralBlockHeight: '1', referredTotalVolume: '0', }; @@ -121,9 +122,10 @@ describe('update-affiliate-info', () => { affiliateEarnings: '500', referredMakerTrades: 0, referredTakerTrades: 1, - totalReferredFees: '1000', + totalReferredMakerFees: '0', + totalReferredTakerFees: '1000', + totalReferredMakerRebates: '0', totalReferredUsers: 2, - referredNetProtocolEarnings: '500', firstReferralBlockHeight: '1', referredTotalVolume: '1', }; @@ -189,9 +191,10 @@ describe('update-affiliate-info', () => { affiliateEarnings: '1000', referredMakerTrades: 0, referredTakerTrades: 2, - totalReferredFees: '2000', + totalReferredMakerFees: '0', + totalReferredTakerFees: '2000', + totalReferredMakerRebates: '0', totalReferredUsers: 1, - referredNetProtocolEarnings: '1000', firstReferralBlockHeight: '1', referredTotalVolume: '2', }; @@ -255,9 +258,10 @@ describe('update-affiliate-info', () => { affiliateEarnings: '1000', referredMakerTrades: 0, referredTakerTrades: 2, - totalReferredFees: '2000', + totalReferredMakerFees: '0', + totalReferredTakerFees: '2000', + totalReferredMakerRebates: '0', totalReferredUsers: 1, - referredNetProtocolEarnings: '1000', firstReferralBlockHeight: '1', referredTotalVolume: '2', }; From c182cd94e4577551c79a5bf95b0f79be7fbecbba Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:06:31 -0400 Subject: [PATCH 017/120] Fix bug with PnL aggregation. (backport #2446) (#2451) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../comlink/__tests__/lib/helpers.test.ts | 77 ++++++++++++------- .../api/v4/historical-pnl-controller.ts | 6 +- .../controllers/api/v4/vault-controller.ts | 42 ++++------ indexer/services/comlink/src/lib/helpers.ts | 39 ++++++---- 4 files changed, 90 insertions(+), 74 deletions(-) diff --git a/indexer/services/comlink/__tests__/lib/helpers.test.ts b/indexer/services/comlink/__tests__/lib/helpers.test.ts index 8c9e27bebf..d814827235 100644 --- a/indexer/services/comlink/__tests__/lib/helpers.test.ts +++ b/indexer/services/comlink/__tests__/lib/helpers.test.ts @@ -44,7 +44,7 @@ import { getPerpetualPositionsWithUpdatedFunding, initializePerpetualPositionsWithFunding, getChildSubaccountNums, - aggregatePnlTicks, + aggregateHourlyPnlTicks, getSubaccountResponse, } from '../../src/lib/helpers'; import _ from 'lodash'; @@ -60,6 +60,7 @@ import { } from '@dydxprotocol-indexer/postgres/build/__tests__/helpers/constants'; import { AssetPositionsMap, PerpetualPositionWithFunding, SubaccountResponseObject } from '../../src/types'; import { ZERO, ZERO_USDC_POSITION } from '../../src/lib/constants'; +import { DateTime } from 'luxon'; describe('helpers', () => { afterEach(async () => { @@ -833,7 +834,7 @@ describe('helpers', () => { }); }); - describe('aggregatePnlTicks', () => { + describe('aggregateHourlyPnlTicks', () => { it('aggregates single pnl tick', () => { const pnlTick: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, @@ -843,10 +844,12 @@ describe('helpers', () => { ), }; - const aggregatedPnlTicks: Map = aggregatePnlTicks([pnlTick]); + const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks([pnlTick]); expect( - aggregatedPnlTicks.get(parseInt(pnlTick.blockHeight, 10)), - ).toEqual(expect.objectContaining({ ...testConstants.defaultPnlTick })); + aggregatedPnlTicks, + ).toEqual( + [expect.objectContaining({ ...testConstants.defaultPnlTick })], + ); }); it('aggregates multiple pnl ticks same height', () => { @@ -865,38 +868,58 @@ describe('helpers', () => { ), }; const blockHeight2: string = '80'; + const blockTime2: string = DateTime.fromISO(pnlTick.createdAt).plus({ hour: 1 }).toISO(); const pnlTick3: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, id: PnlTicksTable.uuid( testConstants.defaultPnlTick.subaccountId, - testConstants.defaultPnlTick.createdAt, + blockTime2, ), blockHeight: blockHeight2, + blockTime: blockTime2, + createdAt: blockTime2, + }; + const blockHeight3: string = '81'; + const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).plus({ minute: 61 }).toISO(); + const pnlTick4: PnlTicksFromDatabase = { + ...testConstants.defaultPnlTick, + id: PnlTicksTable.uuid( + testConstants.defaultPnlTick.subaccountId, + blockTime3, + ), + equity: '1', + totalPnl: '2', + netTransfers: '3', + blockHeight: blockHeight3, + blockTime: blockTime3, + createdAt: blockTime3, }; - const aggregatedPnlTicks: Map = aggregatePnlTicks( - [pnlTick, pnlTick2, pnlTick3], + const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks( + [pnlTick, pnlTick2, pnlTick3, pnlTick4], ); - // Combined pnl tick at initial block height. - expect( - aggregatedPnlTicks.get(parseInt(pnlTick.blockHeight, 10)), - ).toEqual(expect.objectContaining({ - equity: (parseFloat(testConstants.defaultPnlTick.equity) + + expect(aggregatedPnlTicks).toEqual( + expect.arrayContaining([ + // Combined pnl tick at initial hour + expect.objectContaining({ + equity: (parseFloat(testConstants.defaultPnlTick.equity) + parseFloat(pnlTick2.equity)).toString(), - totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) + - parseFloat(pnlTick2.totalPnl)).toString(), - netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) + - parseFloat(pnlTick2.netTransfers)).toString(), - createdAt: testConstants.defaultPnlTick.createdAt, - blockHeight: testConstants.defaultPnlTick.blockHeight, - blockTime: testConstants.defaultPnlTick.blockTime, - })); - // Single pnl tick at second block height. - expect( - aggregatedPnlTicks.get(parseInt(blockHeight2, 10)), - ).toEqual(expect.objectContaining({ - ...pnlTick3, - })); + totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) + + parseFloat(pnlTick2.totalPnl)).toString(), + netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) + + parseFloat(pnlTick2.netTransfers)).toString(), + }), + // Combined pnl tick at initial hour + 1 hour and initial hour + 1 hour, 1 minute + expect.objectContaining({ + equity: (parseFloat(pnlTick3.equity) + + parseFloat(pnlTick4.equity)).toString(), + totalPnl: (parseFloat(pnlTick3.totalPnl) + + parseFloat(pnlTick4.totalPnl)).toString(), + netTransfers: (parseFloat(pnlTick3.netTransfers) + + parseFloat(pnlTick4.netTransfers)).toString(), + }), + ]), + ); }); }); }); diff --git a/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts b/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts index 6ea7a5ce58..96a3131ea9 100644 --- a/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts @@ -19,7 +19,7 @@ import { getReqRateLimiter } from '../../../caches/rate-limiters'; import config from '../../../config'; import { complianceAndGeoCheck } from '../../../lib/compliance-and-geo-check'; import { NotFoundError } from '../../../lib/errors'; -import { aggregatePnlTicks, getChildSubaccountIds, handleControllerError } from '../../../lib/helpers'; +import { aggregateHourlyPnlTicks, getChildSubaccountIds, handleControllerError } from '../../../lib/helpers'; import { rateLimiterMiddleware } from '../../../lib/rate-limit'; import { CheckLimitAndCreatedBeforeOrAtAndOnOrAfterSchema, @@ -156,10 +156,10 @@ class HistoricalPnlController extends Controller { } // aggregate pnlTicks for all subaccounts grouped by blockHeight - const aggregatedPnlTicks: Map = aggregatePnlTicks(pnlTicks); + const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(pnlTicks); return { - historicalPnl: Array.from(aggregatedPnlTicks.values()).map( + historicalPnl: aggregatedPnlTicks.map( (pnlTick: PnlTicksFromDatabase) => { return pnlTicksToResponseObject(pnlTick); }), 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 ee4a31fe64..81f710b315 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -38,7 +38,7 @@ import { import { getReqRateLimiter } from '../../../caches/rate-limiters'; import config from '../../../config'; import { - aggregatePnlTicks, + aggregateHourlyPnlTicks, getSubaccountResponse, handleControllerError, } from '../../../lib/helpers'; @@ -93,7 +93,7 @@ class VaultController extends Controller { ]); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight - const aggregatedPnlTicks: Map = aggregatePnlTicks(vaultPnlTicks); + const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(vaultPnlTicks); const currentEquity: string = Array.from(vaultPositions.values()) .map((position: VaultPosition): string => { @@ -473,46 +473,34 @@ function getPnlTicksWithCurrentTick( } /** - * Takes in a map of block heights to PnlTicks and filters out the closest pnl tick per interval. - * @param pnlTicksByBlock Map of block number to pnl tick. + * Takes in an array of PnlTicks and filters out the closest pnl tick per interval. + * @param pnlTicks Array of pnl ticks. * @param resolution Resolution of interval. * @returns Array of PnlTicksFromDatabase, one per interval. */ function filterOutIntervalTicks( - pnlTicksByBlock: Map, + pnlTicks: PnlTicksFromDatabase[], resolution: PnlTickInterval, ): PnlTicksFromDatabase[] { - // Track block to block time. - const blockToBlockTime: Map = new Map(); - // Track start of days to closest block by block time. - const blocksPerInterval: Map = new Map(); - // Track start of days to closest Pnl tick. + // Track start of intervals to closest Pnl tick. const ticksPerInterval: Map = new Map(); - pnlTicksByBlock.forEach((pnlTick: PnlTicksFromDatabase, block: number): void => { + pnlTicks.forEach((pnlTick: PnlTicksFromDatabase): void => { const blockTime: DateTime = DateTime.fromISO(pnlTick.blockTime).toUTC(); - blockToBlockTime.set(block, blockTime); const startOfInterval: DateTime = blockTime.toUTC().startOf(resolution); const startOfIntervalStr: string = startOfInterval.toISO(); - const startOfIntervalBlock: number | undefined = blocksPerInterval.get(startOfIntervalStr); - // No block for the start of interval, set this block as the block for the interval. - if (startOfIntervalBlock === undefined) { - blocksPerInterval.set(startOfIntervalStr, block); - ticksPerInterval.set(startOfIntervalStr, pnlTick); - return; - } - - const startOfDayBlockTime: DateTime | undefined = blockToBlockTime.get(startOfIntervalBlock); - // Invalid block set as start of day block, set this block as the block for the day. - if (startOfDayBlockTime === undefined) { - blocksPerInterval.set(startOfIntervalStr, block); + const tickForInterval: PnlTicksFromDatabase | undefined = ticksPerInterval.get( + startOfIntervalStr, + ); + // No tick for the start of interval, set this tick as the block for the interval. + if (tickForInterval === undefined) { ticksPerInterval.set(startOfIntervalStr, pnlTick); return; } + const tickPerIntervalBlockTime: DateTime = DateTime.fromISO(tickForInterval.blockTime); - // This block is closer to the start of the day, set it as the block for the day. - if (blockTime.diff(startOfInterval) < startOfDayBlockTime.diff(startOfInterval)) { - blocksPerInterval.set(startOfIntervalStr, block); + // This tick is closer to the start of the interval, set it as the tick for the interval. + if (blockTime.diff(startOfInterval) < tickPerIntervalBlockTime.diff(startOfInterval)) { ticksPerInterval.set(startOfIntervalStr, pnlTick); } }); diff --git a/indexer/services/comlink/src/lib/helpers.ts b/indexer/services/comlink/src/lib/helpers.ts index 6da4106907..b3f5d3bf19 100644 --- a/indexer/services/comlink/src/lib/helpers.ts +++ b/indexer/services/comlink/src/lib/helpers.ts @@ -28,6 +28,7 @@ import { import Big from 'big.js'; import express from 'express'; import _ from 'lodash'; +import { DateTime } from 'luxon'; import config from '../config'; import { @@ -672,32 +673,36 @@ export function getSubaccountResponse( /* ------- PNL HELPERS ------- */ /** - * Aggregates a list of PnL ticks, combining any PnL ticks for the same blockheight by summing + * Aggregates a list of PnL ticks, combining any PnL ticks for the same hour by summing * the equity, totalPnl, and net transfers. * Returns a map of block height to the resulting PnL tick. * @param pnlTicks * @returns */ -export function aggregatePnlTicks( +export function aggregateHourlyPnlTicks( pnlTicks: PnlTicksFromDatabase[], -): Map { - const aggregatedPnlTicks: Map = new Map(); +): PnlTicksFromDatabase[] { + const hourlyPnlTicks: Map = new Map(); for (const pnlTick of pnlTicks) { - const blockHeight: number = parseInt(pnlTick.blockHeight, 10); - if (aggregatedPnlTicks.has(blockHeight)) { - const currentPnlTick: PnlTicksFromDatabase = aggregatedPnlTicks.get( - blockHeight, + const truncatedTime: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').toISO(); + if (hourlyPnlTicks.has(truncatedTime)) { + const aggregatedTick: PnlTicksFromDatabase = hourlyPnlTicks.get( + truncatedTime, ) as PnlTicksFromDatabase; - aggregatedPnlTicks.set(blockHeight, { - ...currentPnlTick, - equity: (parseFloat(currentPnlTick.equity) + parseFloat(pnlTick.equity)).toString(), - totalPnl: (parseFloat(currentPnlTick.totalPnl) + parseFloat(pnlTick.totalPnl)).toString(), - netTransfers: (parseFloat(currentPnlTick.netTransfers) + - parseFloat(pnlTick.netTransfers)).toString(), - }); + hourlyPnlTicks.set( + truncatedTime, + { + ...aggregatedTick, + equity: (parseFloat(aggregatedTick.equity) + parseFloat(pnlTick.equity)).toString(), + totalPnl: (parseFloat(aggregatedTick.totalPnl) + parseFloat(pnlTick.totalPnl)).toString(), + netTransfers: ( + parseFloat(aggregatedTick.netTransfers) + parseFloat(pnlTick.netTransfers) + ).toString(), + }, + ); } else { - aggregatedPnlTicks.set(blockHeight, pnlTick); + hourlyPnlTicks.set(truncatedTime, pnlTick); } } - return aggregatedPnlTicks; + return Array.from(hourlyPnlTicks.values()); } From 939cb56830d9907c91f9b967788000160bd3c816 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:27:48 -0400 Subject: [PATCH 018/120] Get latest hourly tick to compute final tick for megavault PnL. (backport #2454) (#2466) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../api/v4/vault-controller.test.ts | 96 +++++++++++++------ indexer/services/comlink/src/config.ts | 1 + .../controllers/api/v4/vault-controller.ts | 31 ++++++ 3 files changed, 97 insertions(+), 31 deletions(-) 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 b2071c6681..582cb25361 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 @@ -25,20 +25,23 @@ import config from '../../../../src/config'; describe('vault-controller#V4', () => { const latestBlockHeight: string = '25'; - const currentBlockHeight: string = '9'; + const currentHourBlockHeight: string = '10'; + const currentDayBlockHeight: string = '9'; const twoHourBlockHeight: string = '7'; const almostTwoDayBlockHeight: string = '5'; const twoDayBlockHeight: string = '3'; - const currentTime: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 }); - const latestTime: DateTime = currentTime.plus({ second: 5 }); - const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 }); - const twoDaysAgo: DateTime = currentTime.minus({ day: 2 }); - const almostTwoDaysAgo: DateTime = currentTime.minus({ hour: 47 }); + const currentDay: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 }); + const currentHour: DateTime = currentDay.plus({ hour: 1 }); + const latestTime: DateTime = currentDay.plus({ minute: 90 }); + const twoHoursAgo: DateTime = currentDay.minus({ hour: 2 }); + const twoDaysAgo: DateTime = currentDay.minus({ day: 2 }); + const almostTwoDaysAgo: DateTime = currentDay.minus({ hour: 47 }); const initialFundingIndex: string = '10000'; const vault1Equity: number = 159500; const vault2Equity: number = 10000; const mainVaultEquity: number = 10000; const vaultPnlHistoryHoursPrev: number = config.VAULT_PNL_HISTORY_HOURS; + const vaultPnlLastPnlWindowPrev: number = config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS; beforeAll(async () => { await dbHelpers.migrate(); @@ -52,6 +55,8 @@ describe('vault-controller#V4', () => { beforeEach(async () => { // Get a week of data for hourly pnl ticks. config.VAULT_PNL_HISTORY_HOURS = 168; + // Use last 48 hours to get latest pnl tick for tests. + config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = 48; await testMocks.seedData(); await perpetualMarketRefresher.updatePerpetualMarkets(); await liquidityTierRefresher.updateLiquidityTiers(); @@ -68,8 +73,8 @@ describe('vault-controller#V4', () => { }), BlockTable.create({ ...testConstants.defaultBlock, - time: currentTime.toISO(), - blockHeight: currentBlockHeight, + time: currentDay.toISO(), + blockHeight: currentDayBlockHeight, }), BlockTable.create({ ...testConstants.defaultBlock, @@ -81,6 +86,11 @@ describe('vault-controller#V4', () => { time: almostTwoDaysAgo.toISO(), blockHeight: almostTwoDayBlockHeight, }), + BlockTable.create({ + ...testConstants.defaultBlock, + time: currentHour.toISO(), + blockHeight: currentHourBlockHeight, + }), ]); await SubaccountTable.create(testConstants.vaultSubaccount); await SubaccountTable.create({ @@ -114,6 +124,7 @@ describe('vault-controller#V4', () => { afterEach(async () => { await dbHelpers.clearData(); config.VAULT_PNL_HISTORY_HOURS = vaultPnlHistoryHoursPrev; + config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = vaultPnlLastPnlWindowPrev; }); it('Get /megavault/historicalPnl with no vault subaccounts', async () => { @@ -126,13 +137,14 @@ describe('vault-controller#V4', () => { }); it.each([ - ['no resolution', '', [1, 2]], - ['daily resolution', '?resolution=day', [1, 2]], - ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ['no resolution', '', [1, 2], 4], + ['daily resolution', '?resolution=day', [1, 2], 4], + ['hourly resolution', '?resolution=hour', [1, 2, 3, 4], 4], ])('Get /megavault/historicalPnl with single vault subaccount (%s)', async ( _name: string, queryParam: string, expectedTicksIndex: number[], + finalTickIndex: number, ) => { await VaultTable.create({ ...testConstants.defaultVault, @@ -141,7 +153,7 @@ describe('vault-controller#V4', () => { }); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const finalTick: PnlTicksFromDatabase = { - ...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]], + ...createdPnlTicks[finalTickIndex], equity: Big(vault1Equity).toFixed(), blockHeight: latestBlockHeight, blockTime: latestTime.toISO(), @@ -164,14 +176,14 @@ describe('vault-controller#V4', () => { }); it.each([ - ['no resolution', '', [1, 2], [undefined, 6], [9, 10]], - ['daily resolution', '?resolution=day', [1, 2], [undefined, 6], [9, 10]], + ['no resolution', '', [1, 2], [undefined, 7], [11, 12]], + ['daily resolution', '?resolution=day', [1, 2], [undefined, 7], [11, 12]], [ 'hourly resolution', '?resolution=hour', - [1, undefined, 2, 3], - [undefined, 5, 6, 7], - [9, undefined, 10, 11], + [1, undefined, 2, 3, 4], + [undefined, 6, 7, 8, 9], + [11, undefined, 12, 13, 14], ], ])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async ( _name: string, @@ -212,7 +224,8 @@ describe('vault-controller#V4', () => { const expectedPnlTickBase: any = { equity: (parseFloat(testConstants.defaultPnlTick.equity) * 3).toString(), - totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 3).toString(), + // total pnl should be fetched from latest hourly pnl tick. + totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 4).toString(), netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 3).toString(), }; const finalTick: PnlTicksFromDatabase = { @@ -268,7 +281,7 @@ describe('vault-controller#V4', () => { it.each([ ['no resolution', '', [1, 2]], ['daily resolution', '?resolution=day', [1, 2]], - ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ['hourly resolution', '?resolution=hour', [1, 2, 3, 4]], ])('Get /vaults/historicalPnl with single vault subaccount (%s)', async ( _name: string, queryParam: string, @@ -306,9 +319,9 @@ describe('vault-controller#V4', () => { }); it.each([ - ['no resolution', '', [1, 2], [5, 6]], - ['daily resolution', '?resolution=day', [1, 2], [5, 6]], - ['hourly resolution', '?resolution=hour', [1, 2, 3], [5, 6, 7]], + ['no resolution', '', [1, 2], [6, 7]], + ['daily resolution', '?resolution=day', [1, 2], [6, 7]], + ['hourly resolution', '?resolution=hour', [1, 2, 3, 4], [6, 7, 8, 9]], ])('Get /vaults/historicalPnl with 2 vault subaccounts (%s)', async ( _name: string, queryParam: string, @@ -526,9 +539,16 @@ describe('vault-controller#V4', () => { }), PnlTicksTable.create({ ...testConstants.defaultPnlTick, - blockTime: currentTime.toISO(), - createdAt: currentTime.toISO(), - blockHeight: currentBlockHeight, + blockTime: currentDay.toISO(), + createdAt: currentDay.toISO(), + blockHeight: currentDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + totalPnl: (2 * parseFloat(testConstants.defaultPnlTick.totalPnl)).toString(), + blockTime: currentHour.toISO(), + createdAt: currentHour.toISO(), + blockHeight: currentHourBlockHeight, }), PnlTicksTable.create({ ...testConstants.defaultPnlTick, @@ -551,9 +571,16 @@ describe('vault-controller#V4', () => { PnlTicksTable.create({ ...testConstants.defaultPnlTick, subaccountId: testConstants.vaultSubaccountId, - blockTime: currentTime.toISO(), - createdAt: currentTime.toISO(), - blockHeight: currentBlockHeight, + blockTime: currentDay.toISO(), + createdAt: currentDay.toISO(), + blockHeight: currentDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: testConstants.vaultSubaccountId, + blockTime: currentHour.toISO(), + createdAt: currentHour.toISO(), + blockHeight: currentHourBlockHeight, }), ]); @@ -580,9 +607,16 @@ describe('vault-controller#V4', () => { PnlTicksTable.create({ ...testConstants.defaultPnlTick, subaccountId: MEGAVAULT_SUBACCOUNT_ID, - blockTime: currentTime.toISO(), - createdAt: currentTime.toISO(), - blockHeight: currentBlockHeight, + blockTime: currentDay.toISO(), + createdAt: currentDay.toISO(), + blockHeight: currentDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: MEGAVAULT_SUBACCOUNT_ID, + blockTime: currentHour.toISO(), + createdAt: currentHour.toISO(), + blockHeight: currentHourBlockHeight, }), ]); createdTicks.push(...mainSubaccountTicks); diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index 1b70d73b4b..743bae1dd4 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -62,6 +62,7 @@ export const configSchema = { // Vaults config VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }), VAULT_PNL_HISTORY_HOURS: parseInteger({ default: 72 }), + VAULT_LATEST_PNL_TICK_WINDOW_HOURS: parseInteger({ default: 1 }), }; //////////////////////////////////////////////////////////////////////////////// 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 81f710b315..d5e8ff5c42 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -80,16 +80,19 @@ class VaultController extends Controller { vaultPositions, latestBlock, mainSubaccountEquity, + latestPnlTick, ] : [ PnlTicksFromDatabase[], Map, BlockFromDatabase, string, + PnlTicksFromDatabase | undefined, ] = await Promise.all([ getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, getResolution(resolution)), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), getMainSubaccountEquity(), + getLatestPnlTick(vaultSubaccountIdsWithMainSubaccount), ]); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight @@ -105,6 +108,7 @@ class VaultController extends Controller { currentEquity, filterOutIntervalTicks(aggregatedPnlTicks, getResolution(resolution)), latestBlock, + latestPnlTick, ); return { @@ -458,7 +462,17 @@ function getPnlTicksWithCurrentTick( equity: string, pnlTicks: PnlTicksFromDatabase[], latestBlock: BlockFromDatabase, + latestTick: PnlTicksFromDatabase | undefined = undefined, ): PnlTicksFromDatabase[] { + if (latestTick !== undefined) { + return pnlTicks.concat({ + ...latestTick, + equity, + blockHeight: latestBlock.blockHeight, + blockTime: latestBlock.time, + createdAt: latestBlock.time, + }); + } if (pnlTicks.length === 0) { return []; } @@ -472,6 +486,23 @@ function getPnlTicksWithCurrentTick( return pnlTicks.concat([currentTick]); } +export async function getLatestPnlTick( + vaultSubaccountIds: string[], +): Promise { + const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( + PnlTickInterval.hour, + config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS * 60 * 60, + vaultSubaccountIds, + ); + // Aggregate and get pnl tick closest to the hour + const aggregatedTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(pnlTicks); + const filteredTicks: PnlTicksFromDatabase[] = filterOutIntervalTicks( + aggregatedTicks, + PnlTickInterval.hour, + ); + return _.maxBy(filteredTicks, 'blockTime'); +} + /** * Takes in an array of PnlTicks and filters out the closest pnl tick per interval. * @param pnlTicks Array of pnl ticks. From 6800a368c2ce72948be59484b701fc221ebff8d3 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:02:13 -0400 Subject: [PATCH 019/120] add afflaiteReferredMakerRebates field to response (backport #2473) (#2474) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- .../controllers/api/v4/affiliates-controller.test.ts | 1 + indexer/services/comlink/public/api-documentation.md | 10 +++++++--- indexer/services/comlink/public/swagger.json | 7 ++++++- .../src/controllers/api/v4/affiliates-controller.ts | 1 + indexer/services/comlink/src/types.ts | 1 + 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts index 30ceebd062..ee77111d30 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/affiliates-controller.test.ts @@ -380,5 +380,6 @@ function affiliateInfoCreateToResponseObject( affiliateReferredTotalVolume: Number(info.referredTotalVolume), affiliateReferredMakerFees: Number(info.totalReferredMakerFees), affiliateReferredTakerFees: Number(info.totalReferredTakerFees), + affiliateReferredMakerRebates: Number(info.totalReferredMakerRebates), }; } diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index eaec0a2fbe..a7ac9f0000 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -655,7 +655,8 @@ fetch(`${baseURL}/affiliates/snapshot`, "affiliateReferredNetProtocolEarnings": 0.1, "affiliateReferredTotalVolume": 0.1, "affiliateReferredMakerFees": 0.1, - "affiliateReferredTakerFees": 0.1 + "affiliateReferredTakerFees": 0.1, + "affiliateReferredMakerRebates": 0.1 } ], "total": 0.1, @@ -4248,7 +4249,8 @@ This operation does not require authentication "affiliateReferredNetProtocolEarnings": 0.1, "affiliateReferredTotalVolume": 0.1, "affiliateReferredMakerFees": 0.1, - "affiliateReferredTakerFees": 0.1 + "affiliateReferredTakerFees": 0.1, + "affiliateReferredMakerRebates": 0.1 } ``` @@ -4267,6 +4269,7 @@ This operation does not require authentication |affiliateReferredTotalVolume|number(double)|true|none|none| |affiliateReferredMakerFees|number(double)|true|none|none| |affiliateReferredTakerFees|number(double)|true|none|none| +|affiliateReferredMakerRebates|number(double)|true|none|none| ## AffiliateSnapshotResponse @@ -4288,7 +4291,8 @@ This operation does not require authentication "affiliateReferredNetProtocolEarnings": 0.1, "affiliateReferredTotalVolume": 0.1, "affiliateReferredMakerFees": 0.1, - "affiliateReferredTakerFees": 0.1 + "affiliateReferredTakerFees": 0.1, + "affiliateReferredMakerRebates": 0.1 } ], "total": 0.1, diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index e94a095d65..0737485b43 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -311,6 +311,10 @@ "affiliateReferredTakerFees": { "type": "number", "format": "double" + }, + "affiliateReferredMakerRebates": { + "type": "number", + "format": "double" } }, "required": [ @@ -323,7 +327,8 @@ "affiliateReferredNetProtocolEarnings", "affiliateReferredTotalVolume", "affiliateReferredMakerFees", - "affiliateReferredTakerFees" + "affiliateReferredTakerFees", + "affiliateReferredMakerRebates" ], "type": "object", "additionalProperties": false diff --git a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts index ac246bbfdf..c87ba90c09 100644 --- a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts @@ -175,6 +175,7 @@ class AffiliatesController extends Controller { affiliateReferredTotalVolume: Number(info.referredTotalVolume), affiliateReferredMakerFees: Number(info.totalReferredMakerFees), affiliateReferredTakerFees: Number(info.totalReferredTakerFees), + affiliateReferredMakerRebates: Number(info.totalReferredMakerRebates), })); const response: AffiliateSnapshotResponse = { diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 81eace3303..0e0a57512c 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -733,6 +733,7 @@ export interface AffiliateSnapshotResponseObject { affiliateReferredTotalVolume: number, affiliateReferredMakerFees: number, affiliateReferredTakerFees: number, + affiliateReferredMakerRebates: number, } export interface AffiliateTotalVolumeResponse { From 4b19a59e10eee7b7e6a528ccbafa29574202f3ee Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:03:07 -0400 Subject: [PATCH 020/120] [OTE-846] Bazooka sequential clear (backport #2423) (#2477) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- indexer/services/bazooka/src/index.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/indexer/services/bazooka/src/index.ts b/indexer/services/bazooka/src/index.ts index 623a97a90b..8329bd69a0 100644 --- a/indexer/services/bazooka/src/index.ts +++ b/indexer/services/bazooka/src/index.ts @@ -264,14 +264,17 @@ async function partitionKafkaTopics(): Promise { async function clearKafkaTopics( existingKafkaTopics: string[], ): Promise { - await Promise.all( - _.map(KAFKA_TOPICS, - clearKafkaTopic.bind(null, - 1, - config.CLEAR_KAFKA_TOPIC_RETRY_MS, - config.CLEAR_KAFKA_TOPIC_MAX_RETRIES, - existingKafkaTopics)), - ); + // Concurrent calls to clear all topics caused the failure: + // TypeError: Cannot destructure property 'partitions' of 'high.pop(...)' as it is undefined. + for (const topic of KAFKA_TOPICS) { + await clearKafkaTopic( + 1, + config.CLEAR_KAFKA_TOPIC_RETRY_MS, + config.CLEAR_KAFKA_TOPIC_MAX_RETRIES, + existingKafkaTopics, + topic, + ); + } } export async function clearKafkaTopic( From ca6c044542c451395ed151243a14f652d2164e32 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:22:41 -0400 Subject: [PATCH 021/120] [OTE-863] update username generation query (backport #2482) (#2483) Co-authored-by: Mohammed Affan --- .../postgres/src/stores/subaccount-usernames-table.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts b/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts index a60b1c6da8..72a894ce58 100644 --- a/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts +++ b/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts @@ -103,10 +103,9 @@ export async function getSubaccountsWithoutUsernames( const queryString: string = ` SELECT id as "subaccountId" FROM subaccounts - WHERE id NOT IN ( - SELECT "subaccountId" FROM subaccount_usernames - ) - AND subaccounts."subaccountNumber"=0 + WHERE subaccounts."subaccountNumber" = 0 + EXCEPT + SELECT "subaccountId" FROM subaccount_usernames; `; const result: { From 071aa313abf014592e8050d9308bf7a4346d9b77 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:20:42 -0400 Subject: [PATCH 022/120] Improve vault endpoint performance. (backport #2475) (#2484) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../funding-index-updates-table.test.ts | 34 +++++++ .../src/stores/funding-index-updates-table.ts | 75 +++++++++++++- .../controllers/api/v4/vault-controller.ts | 99 +++++++++++-------- 3 files changed, 164 insertions(+), 44 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/funding-index-updates-table.test.ts b/indexer/packages/postgres/__tests__/stores/funding-index-updates-table.test.ts index d42df73764..de7daaa34e 100644 --- a/indexer/packages/postgres/__tests__/stores/funding-index-updates-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/funding-index-updates-table.test.ts @@ -242,4 +242,38 @@ describe('funding index update store', () => { expect(fundingIndexMap[defaultPerpetualMarket2.id]).toEqual(Big(0)); }, ); + + it('Successfully finds funding index maps for multiple effectiveBeforeOrAtHeights', async () => { + const fundingIndexUpdates2: FundingIndexUpdatesCreateObject = { + ...defaultFundingIndexUpdate, + fundingIndex: '124', + effectiveAtHeight: updatedHeight, + effectiveAt: '1982-05-25T00:00:00.000Z', + eventId: defaultTendermintEventId2, + }; + const fundingIndexUpdates3: FundingIndexUpdatesCreateObject = { + ...defaultFundingIndexUpdate, + eventId: defaultTendermintEventId3, + perpetualId: defaultPerpetualMarket2.id, + }; + await Promise.all([ + FundingIndexUpdatesTable.create(defaultFundingIndexUpdate), + FundingIndexUpdatesTable.create(fundingIndexUpdates2), + FundingIndexUpdatesTable.create(fundingIndexUpdates3), + ]); + + const fundingIndexMaps: {[blockHeight:string]: FundingIndexMap} = await FundingIndexUpdatesTable + .findFundingIndexMaps( + ['3', '6'], + ); + + expect(fundingIndexMaps['3'][defaultFundingIndexUpdate.perpetualId]) + .toEqual(Big(defaultFundingIndexUpdate.fundingIndex)); + expect(fundingIndexMaps['3'][fundingIndexUpdates3.perpetualId]) + .toEqual(Big(fundingIndexUpdates3.fundingIndex)); + expect(fundingIndexMaps['6'][defaultFundingIndexUpdate.perpetualId]) + .toEqual(Big(fundingIndexUpdates2.fundingIndex)); + expect(fundingIndexMaps['6'][fundingIndexUpdates3.perpetualId]) + .toEqual(Big(fundingIndexUpdates3.fundingIndex)); + }); }); diff --git a/indexer/packages/postgres/src/stores/funding-index-updates-table.ts b/indexer/packages/postgres/src/stores/funding-index-updates-table.ts index dce9a47028..8ef55a3537 100644 --- a/indexer/packages/postgres/src/stores/funding-index-updates-table.ts +++ b/indexer/packages/postgres/src/stores/funding-index-updates-table.ts @@ -3,6 +3,7 @@ import _ from 'lodash'; import { QueryBuilder } from 'objection'; import { BUFFER_ENCODING_UTF_8, DEFAULT_POSTGRES_OPTIONS } from '../constants'; +import { knexReadReplica } from '../helpers/knex'; import { setupBaseQuery, verifyAllRequiredFields } from '../helpers/stores-helpers'; import Transaction from '../helpers/transaction'; import { getUuid } from '../helpers/uuid'; @@ -21,6 +22,14 @@ import { } from '../types'; import * as PerpetualMarketTable from './perpetual-market-table'; +// Assuming block time of 1 second, this should be 4 hours of blocks +const FOUR_HOUR_OF_BLOCKS = Big(3600).times(4); +// Type used for querying for funding index maps for multiple effective heights. +interface FundingIndexUpdatesFromDatabaseWithSearchHeight extends FundingIndexUpdatesFromDatabase { + // max effective height being queried for + searchHeight: string, +} + export function uuid( blockHeight: string, eventId: Buffer, @@ -193,8 +202,6 @@ export async function findFundingIndexMap( options, ); - // Assuming block time of 1 second, this should be 4 hours of blocks - const FOUR_HOUR_OF_BLOCKS = Big(3600).times(4); const fundingIndexUpdates: FundingIndexUpdatesFromDatabase[] = await baseQuery .distinctOn(FundingIndexUpdatesColumns.perpetualId) .where(FundingIndexUpdatesColumns.effectiveAtHeight, '<=', effectiveBeforeOrAtHeight) @@ -216,3 +223,67 @@ export async function findFundingIndexMap( initialFundingIndexMap, ); } + +/** + * Finds funding index maps for multiple effective before or at heights. Uses a SQL query unnesting + * an array of effective before or at heights and cross-joining with the funding index updates table + * to find the closest funding index update per effective before or at height. + * @param effectiveBeforeOrAtHeights Heights to get funding index maps for. + * @param options + * @returns Object mapping block heights to the respective funding index maps. + */ +export async function findFundingIndexMaps( + effectiveBeforeOrAtHeights: string[], + options: Options = DEFAULT_POSTGRES_OPTIONS, +): Promise<{[blockHeight: string]: FundingIndexMap}> { + const heightNumbers: number[] = effectiveBeforeOrAtHeights + .map((height: string):number => parseInt(height, 10)) + .filter((parsedHeight: number): boolean => { return !Number.isNaN(parsedHeight); }) + .sort(); + // Get the min height to limit the search to blocks 4 hours or before the min height. + const minHeight: number = heightNumbers[0]; + + const result: { + rows: FundingIndexUpdatesFromDatabaseWithSearchHeight[], + } = await knexReadReplica.getConnection().raw( + ` + SELECT + DISTINCT ON ("perpetualId", "searchHeight") "perpetualId", "searchHeight", + "funding_index_updates".* + FROM + "funding_index_updates", + unnest(ARRAY[${heightNumbers.join(',')}]) AS "searchHeight" + WHERE + "effectiveAtHeight" > ${Big(minHeight).minus(FOUR_HOUR_OF_BLOCKS).toFixed()} AND + "effectiveAtHeight" <= "searchHeight" + ORDER BY + "perpetualId", + "searchHeight", + "effectiveAtHeight" DESC + `, + ) as unknown as { + rows: FundingIndexUpdatesFromDatabaseWithSearchHeight[], + }; + + const perpetualMarkets: PerpetualMarketFromDatabase[] = await PerpetualMarketTable.findAll( + {}, + [], + options, + ); + + const fundingIndexMaps:{[blockHeight: string]: FundingIndexMap} = {}; + for (const height of effectiveBeforeOrAtHeights) { + fundingIndexMaps[height] = _.reduce(perpetualMarkets, + (acc: FundingIndexMap, perpetualMarket: PerpetualMarketFromDatabase): FundingIndexMap => { + acc[perpetualMarket.id] = Big(0); + return acc; + }, + {}, + ); + } + for (const funding of result.rows) { + fundingIndexMaps[funding.searchHeight][funding.perpetualId] = Big(funding.fundingIndex); + } + + return fundingIndexMaps; +} 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 d5e8ff5c42..9480b096f1 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -375,10 +375,23 @@ async function getVaultPositions( BlockTable.getLatest(), ]); - const latestFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable - .findFundingIndexMap( - latestBlock.blockHeight, - ); + const updatedAtHeights: string[] = _(subaccounts).map('updatedAtHeight').uniq().value(); + const [ + latestFundingIndexMap, + fundingIndexMaps, + ]: [ + FundingIndexMap, + {[blockHeight: string]: FundingIndexMap} + ] = await Promise.all([ + FundingIndexUpdatesTable + .findFundingIndexMap( + latestBlock.blockHeight, + ), + FundingIndexUpdatesTable + .findFundingIndexMaps( + updatedAtHeights, + ), + ]); const assetPositionsBySubaccount: { [subaccountId: string]: AssetPositionFromDatabase[] } = _.groupBy( assetPositions, @@ -397,47 +410,49 @@ async function getVaultPositions( const vaultPositionsAndSubaccountId: { position: VaultPosition, subaccountId: string, - }[] = await Promise.all( - subaccounts.map(async (subaccount: SubaccountFromDatabase) => { - const perpetualMarket: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher - .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id]); - if (perpetualMarket === undefined) { - throw new Error( - `Vault clob pair id ${vaultSubaccounts[subaccount.id]} does not correspond to a ` + + }[] = subaccounts.map((subaccount: SubaccountFromDatabase) => { + const perpetualMarket: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher + .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id]); + if (perpetualMarket === undefined) { + throw new Error( + `Vault clob pair id ${vaultSubaccounts[subaccount.id]} does not correspond to a ` + 'perpetual market.'); - } - const lastUpdatedFundingIndexMap: FundingIndexMap = await FundingIndexUpdatesTable - .findFundingIndexMap( - subaccount.updatedAtHeight, - ); - - const subaccountResponse: SubaccountResponseObject = getSubaccountResponse( - subaccount, - openPerpetualPositionsBySubaccount[subaccount.id] || [], - assetPositionsBySubaccount[subaccount.id] || [], - assets, - markets, - perpetualMarketRefresher.getPerpetualMarketsMap(), - latestBlock.blockHeight, - latestFundingIndexMap, - lastUpdatedFundingIndexMap, + } + const lastUpdatedFundingIndexMap: FundingIndexMap = fundingIndexMaps[ + subaccount.updatedAtHeight + ]; + if (lastUpdatedFundingIndexMap === undefined) { + throw new Error( + `No funding indices could be found for vault with subaccount ${subaccount.id}`, ); + } - return { - position: { - ticker: perpetualMarket.ticker, - assetPosition: subaccountResponse.assetPositions[ - assetIdToAsset[USDC_ASSET_ID].symbol - ], - perpetualPosition: subaccountResponse.openPerpetualPositions[ - perpetualMarket.ticker - ] || undefined, - equity: subaccountResponse.equity, - }, - subaccountId: subaccount.id, - }; - }), - ); + const subaccountResponse: SubaccountResponseObject = getSubaccountResponse( + subaccount, + openPerpetualPositionsBySubaccount[subaccount.id] || [], + assetPositionsBySubaccount[subaccount.id] || [], + assets, + markets, + perpetualMarketRefresher.getPerpetualMarketsMap(), + latestBlock.blockHeight, + latestFundingIndexMap, + lastUpdatedFundingIndexMap, + ); + + return { + position: { + ticker: perpetualMarket.ticker, + assetPosition: subaccountResponse.assetPositions[ + assetIdToAsset[USDC_ASSET_ID].symbol + ], + perpetualPosition: subaccountResponse.openPerpetualPositions[ + perpetualMarket.ticker + ] || undefined, + equity: subaccountResponse.equity, + }, + subaccountId: subaccount.id, + }; + }); return new Map(vaultPositionsAndSubaccountId.map( (obj: { position: VaultPosition, subaccountId: string }) : [string, VaultPosition] => { From 7a2200ec883892cec3862e536c11298b479b85f9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:24:33 -0400 Subject: [PATCH 023/120] Return undefined from getOrderbookMidPriceMap (backport #2441) (#2486) Co-authored-by: Adam Fraser --- .../__tests__/lib/candles-generator.test.ts | 216 ++---------------- .../ender/src/lib/candles-generator.ts | 8 +- 2 files changed, 14 insertions(+), 210 deletions(-) diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index d58ebd0d2a..cd014d3eaf 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -137,8 +137,8 @@ describe('candleHelper', () => { id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), startedAt: currentStartedAt, resolution, - orderbookMidPriceClose: '105000', - orderbookMidPriceOpen: '105000', + orderbookMidPriceClose: null, + orderbookMidPriceOpen: null, }; }, ); @@ -187,8 +187,8 @@ describe('candleHelper', () => { startedAt: currentStartedAt, resolution, startingOpenInterest: openInterest, - orderbookMidPriceClose: '80500', - orderbookMidPriceOpen: '80500', + orderbookMidPriceClose: null, + orderbookMidPriceOpen: null, }; }, ); @@ -311,8 +311,8 @@ describe('candleHelper', () => { usdVolume: '0', trades: 0, startingOpenInterest: '100', - orderbookMidPriceClose: '1000', - orderbookMidPriceOpen: '1000', + orderbookMidPriceClose: null, + orderbookMidPriceOpen: null, }, true, 1000, @@ -342,8 +342,8 @@ describe('candleHelper', () => { startedAt, resolution: CandleResolution.ONE_MINUTE, startingOpenInterest: '100', - orderbookMidPriceClose: '1000', - orderbookMidPriceOpen: '1000', + orderbookMidPriceClose: null, + orderbookMidPriceOpen: null, }, true, // contains kafka messages 1000, // orderbook mid price @@ -471,196 +471,6 @@ describe('candleHelper', () => { expectTimingStats(); }); - it('Updates previous candle orderBookMidPriceClose if startTime is past candle resolution', async () => { - // Create existing candles - const existingPrice: string = '7000'; - const startingOpenInterest: string = '200'; - const baseTokenVolume: string = '10'; - const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); - const orderbookMidPriceClose = '7500'; - const orderbookMidPriceOpen = '8000'; - await Promise.all( - _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { - return CandleTable.create({ - startedAt: previousStartedAt, - ticker: testConstants.defaultPerpetualMarket.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume, - usdVolume, - trades: existingTrades, - startingOpenInterest, - orderbookMidPriceClose, - orderbookMidPriceOpen, - }); - }), - ); - await startCandleCache(); - - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); - - const publisher: KafkaPublisher = new KafkaPublisher(); - publisher.addEvents([ - defaultTradeKafkaEvent, - defaultTradeKafkaEvent2, - ]); - - // Create new candles, with trades - await runUpdateCandles(publisher).then(async () => { - - // Verify previous candles have orderbookMidPriceClose updated - const previousExpectedCandles: CandleFromDatabase[] = _.map( - Object.values(CandleResolution), - (resolution: CandleResolution) => { - return { - id: CandleTable.uuid(previousStartedAt, defaultCandle.ticker, resolution), - startedAt: previousStartedAt, - ticker: defaultCandle.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume, - usdVolume, - trades: existingTrades, - startingOpenInterest, - orderbookMidPriceClose: '10005', - orderbookMidPriceOpen, - }; - }, - ); - await verifyCandlesInPostgres(previousExpectedCandles); - }); - - // Verify new candles were created - const expectedCandles: CandleFromDatabase[] = _.map( - Object.values(CandleResolution), - (resolution: CandleResolution) => { - const currentStartedAt: IsoString = helpers.calculateNormalizedCandleStartTime( - testConstants.createdDateTime, - resolution, - ).toISO(); - - return { - id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), - startedAt: currentStartedAt, - ticker: defaultCandle.ticker, - resolution, - low: '10000', - high: defaultPrice2, - open: '10000', - close: defaultPrice2, - baseTokenVolume: '20', - usdVolume: '250000', - trades: 2, - startingOpenInterest: '0', - orderbookMidPriceClose: '10005', - orderbookMidPriceOpen: '10005', - }; - }, - ); - await verifyCandlesInPostgres(expectedCandles); - await validateCandlesCache(); - expectTimingStats(); - }); - - it('creates an empty candle and updates the previous candle orderBookMidPriceClose if startTime is past candle resolution', async () => { - // Create existing candles - const existingPrice: string = '7000'; - const startingOpenInterest: string = '200'; - const baseTokenVolume: string = '10'; - const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); - const orderbookMidPriceClose = '7500'; - const orderbookMidPriceOpen = '8000'; - - await Promise.all( - _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { - return CandleTable.create({ - startedAt: previousStartedAt, - ticker: testConstants.defaultPerpetualMarket.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume, - usdVolume, - trades: existingTrades, - startingOpenInterest, - orderbookMidPriceClose, - orderbookMidPriceOpen, - }); - }), - ); - await startCandleCache(); - - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); - - const publisher: KafkaPublisher = new KafkaPublisher(); - publisher.addEvents([]); - - // Create new candles, without trades - await runUpdateCandles(publisher); - - // Verify previous candles have orderbookMidPriceClose updated - const previousExpectedCandles: CandleFromDatabase[] = _.map( - Object.values(CandleResolution), - (resolution: CandleResolution) => { - return { - id: CandleTable.uuid(previousStartedAt, defaultCandle.ticker, resolution), - startedAt: previousStartedAt, - ticker: defaultCandle.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume, - usdVolume, - trades: existingTrades, - startingOpenInterest, - orderbookMidPriceClose: '10005', - orderbookMidPriceOpen, - }; - }, - ); - await verifyCandlesInPostgres(previousExpectedCandles); - - // Verify new empty candle was created - const expectedCandles: CandleFromDatabase[] = _.map( - Object.values(CandleResolution), - (resolution: CandleResolution) => { - const currentStartedAt: IsoString = helpers.calculateNormalizedCandleStartTime( - testConstants.createdDateTime, - resolution, - ).toISO(); - - return { - id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), - startedAt: currentStartedAt, - ticker: defaultCandle.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume: '0', - usdVolume: '0', - trades: 0, - startingOpenInterest: '0', - orderbookMidPriceClose: '10005', - orderbookMidPriceOpen: '10005', - }; - }, - ); - await verifyCandlesInPostgres(expectedCandles); - - }); - it('successfully creates an orderbook price map for each market', async () => { await Promise.all([ OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), @@ -670,11 +480,11 @@ describe('candleHelper', () => { const map = await getOrderbookMidPriceMap(); expect(map).toEqual({ - 'BTC-USD': '105000', - 'ETH-USD': '150000', - 'ISO-USD': '115000', - 'ISO2-USD': null, - 'SHIB-USD': null, + 'BTC-USD': undefined, + 'ETH-USD': undefined, + 'ISO-USD': undefined, + 'ISO2-USD': undefined, + 'SHIB-USD': undefined, }); }); }); diff --git a/indexer/services/ender/src/lib/candles-generator.ts b/indexer/services/ender/src/lib/candles-generator.ts index b232a66eb0..f1daa75f06 100644 --- a/indexer/services/ender/src/lib/candles-generator.ts +++ b/indexer/services/ender/src/lib/candles-generator.ts @@ -20,7 +20,6 @@ import { TradeMessageContents, helpers, } from '@dydxprotocol-indexer/postgres'; -import { OrderbookMidPricesCache } from '@dydxprotocol-indexer/redis'; import { CandleMessage } from '@dydxprotocol-indexer/v4-protos'; import Big from 'big.js'; import _ from 'lodash'; @@ -28,7 +27,6 @@ import { DateTime } from 'luxon'; import { getCandle } from '../caches/candle-cache'; import config from '../config'; -import { redisClient } from '../helpers/redis/redis-controller'; import { KafkaPublisher } from './kafka-publisher'; import { ConsolidatedKafkaEvent, SingleTradeMessage } from './types'; @@ -538,11 +536,7 @@ export async function getOrderbookMidPriceMap(): Promise<{ [ticker: string]: Ord const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()); const promises = perpetualMarkets.map(async (perpetualMarket: PerpetualMarketFromDatabase) => { - const price = await OrderbookMidPricesCache.getMedianPrice( - redisClient, - perpetualMarket.ticker, - ); - return { [perpetualMarket.ticker]: price === undefined ? undefined : price }; + return Promise.resolve({ [perpetualMarket.ticker]: undefined }); }); const pricesArray = await Promise.all(promises); From 54b3bced767db99e461a2d8a63e14b7990287ae5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:25:42 -0400 Subject: [PATCH 024/120] [CT-629] Fix entryPrice calc (backport #2455) (#2496) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- .../order-fills/liquidation-handler.test.ts | 4 ++-- .../order-fills/order-handler.test.ts | 22 ++++++++++++++++--- ...ydx_liquidation_fill_handler_per_order.sql | 2 +- ...te_perpetual_position_aggregate_fields.sql | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) 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 a5cc41f3d6..805ca676f0 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: '10', + size: '5', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -392,7 +392,7 @@ describe('LiquidationHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.sumOpen!).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 ba9a62ab34..65cb1c0422 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: '10', + size: '5', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -212,6 +212,7 @@ describe('OrderHandler', () => { { goodTilBlock: 15, }, + false, ], [ 'goodTilBlockTime', @@ -221,6 +222,17 @@ 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 ' + @@ -229,6 +241,7 @@ describe('OrderHandler', () => { _name: string, makerGoodTilOneof: Partial, takerGoodTilOneof: Partial, + useNegativeSize: boolean, ) => { const transactionIndex: number = 0; const eventIndex: number = 0; @@ -284,7 +297,10 @@ describe('OrderHandler', () => { // create PerpetualPositions await Promise.all([ - PerpetualPositionTable.create(defaultPerpetualPosition), + PerpetualPositionTable.create({ + ...defaultPerpetualPosition, + size: useNegativeSize ? '-5' : defaultPerpetualPosition.size, + }), PerpetualPositionTable.create({ ...defaultPerpetualPosition, subaccountId: testConstants.defaultSubaccountId2, @@ -439,7 +455,7 @@ describe('OrderHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.sumOpen!).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 493b1257d6..dc3dfa5e4c 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", perpetual_position_record."sumOpen", + perpetual_position_record."entryPrice", ABS(perpetual_position_record."size"), 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 d021eecf28..f6e269a0b1 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", perpetual_position_record."sumOpen", price, size + perpetual_position_record."entryPrice", ABS(perpetual_position_record."size"), price, size ); perpetual_position_record."sumOpen" = sum_open; perpetual_position_record."entryPrice" = entry_price; From 666898fc6fefd2c785d9294b9752e1a1548a74ad Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:27:21 -0400 Subject: [PATCH 025/120] Don't increment messageId for custom ping messages (backport #2493) (#2497) Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> --- indexer/services/socks/src/websocket/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/indexer/services/socks/src/websocket/index.ts b/indexer/services/socks/src/websocket/index.ts index 795f6a7527..1906d3a72e 100644 --- a/indexer/services/socks/src/websocket/index.ts +++ b/indexer/services/socks/src/websocket/index.ts @@ -243,8 +243,6 @@ export class Index { return; } - this.connections[connectionId].messageId += 1; - const messageStr = message.toString(); let parsed: IncomingMessage; @@ -282,6 +280,8 @@ export class Index { messageContents: safeJsonStringify(message), }); + this.connections[connectionId].messageId += 1; + // Do not wait for this. this.subscriptions.subscribe( this.connections[connectionId].ws, @@ -311,6 +311,8 @@ export class Index { unsubscribeMessage.id, ); + this.connections[connectionId].messageId += 1; + sendMessage( this.connections[connectionId].ws, connectionId, From 5042763fa0b8ba6cbbdddf8fc18432eb5b251abc Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:08:13 -0400 Subject: [PATCH 026/120] [OTE-880] Emit log in case of collisions (backport #2500) (#2504) Co-authored-by: Mohammed Affan --- .../tasks/subaccount-username-generator.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts index af0312481c..819afa5bfd 100644 --- a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts +++ b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts @@ -1,9 +1,10 @@ -import { logger } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { SubaccountUsernamesTable, SubaccountsWithoutUsernamesResult, } from '@dydxprotocol-indexer/postgres'; +import config from '../config'; import { generateUsername } from '../helpers/usernames-helper'; export default async function runTask(): Promise { @@ -21,13 +22,18 @@ export default async function runTask(): Promise { subaccountId: subaccount.subaccountId, }); } catch (e) { - logger.error({ - at: 'subaccount-username-generator#runTask', - message: 'Failed to insert username for subaccount', - subaccountId: subaccount.subaccountId, - username, - error: e, - }); + if (e instanceof Error && e.name === 'UniqueViolationError') { + stats.increment( + `${config.SERVICE_NAME}.subaccount-username-generator.collision`, 1); + } else { + logger.error({ + at: 'subaccount-username-generator#runTask', + message: 'Failed to insert username for subaccount', + subaccountId: subaccount.subaccountId, + username, + error: e, + }); + } } } } From 3339df5e1a80e30a75f0dd83f99d6980cfde9833 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:25:01 -0400 Subject: [PATCH 027/120] [OTE-876] update roundtable loop timings for instrumentation and uncrossing (backport #2494) (#2506) Co-authored-by: Mohammed Affan --- indexer/services/roundtable/src/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 42b66a4882..34dafba44b 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -70,7 +70,7 @@ export const configSchema = { default: 2 * ONE_MINUTE_IN_MILLISECONDS, }), LOOPS_INTERVAL_MS_UNCROSS_ORDERBOOK: parseInteger({ - default: THIRTY_SECONDS_IN_MILLISECONDS, + default: 15 * ONE_SECOND_IN_MILLISECONDS, }), LOOPS_INTERVAL_MS_PNL_TICKS: parseInteger({ default: THIRTY_SECONDS_IN_MILLISECONDS, @@ -79,7 +79,7 @@ export const configSchema = { default: 2 * ONE_MINUTE_IN_MILLISECONDS, }), LOOPS_INTERVAL_MS_ORDERBOOK_INSTRUMENTATION: parseInteger({ - default: 5 * ONE_SECOND_IN_MILLISECONDS, + default: 1 * ONE_MINUTE_IN_MILLISECONDS, }), LOOPS_INTERVAL_MS_PNL_INSTRUMENTATION: parseInteger({ default: ONE_HOUR_IN_MILLISECONDS, From e2298c430bbdd6db080116fb0400f9fc3fa7f3ff Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:58:02 -0400 Subject: [PATCH 028/120] Remove orderbook cache roundtable job (backport #2510) (#2511) Co-authored-by: Adam Fraser --- .../tasks/cache-orderbook-mid-prices.test.ts | 98 ------------------- indexer/services/roundtable/src/config.ts | 1 - indexer/services/roundtable/src/index.ts | 9 -- .../src/tasks/cache-orderbook-mid-prices.ts | 40 -------- 4 files changed, 148 deletions(-) delete mode 100644 indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts delete mode 100644 indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts diff --git a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts deleted file mode 100644 index cd0eee3970..0000000000 --- a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { - dbHelpers, - testConstants, - testMocks, -} from '@dydxprotocol-indexer/postgres'; -import { - OrderbookMidPricesCache, - OrderbookLevelsCache, - redis, -} from '@dydxprotocol-indexer/redis'; -import { redisClient } from '../../src/helpers/redis'; -import runTask from '../../src/tasks/cache-orderbook-mid-prices'; - -jest.mock('@dydxprotocol-indexer/base', () => ({ - ...jest.requireActual('@dydxprotocol-indexer/base'), - logger: { - info: jest.fn(), - error: jest.fn(), - }, -})); - -jest.mock('@dydxprotocol-indexer/redis', () => ({ - ...jest.requireActual('@dydxprotocol-indexer/redis'), - OrderbookLevelsCache: { - getOrderBookMidPrice: jest.fn(), - }, -})); - -describe('cache-orderbook-mid-prices', () => { - beforeAll(async () => { - await dbHelpers.migrate(); - }); - - beforeEach(async () => { - await dbHelpers.clearData(); - await redis.deleteAllAsync(redisClient); - await testMocks.seedData(); - }); - - afterAll(async () => { - await dbHelpers.teardown(); - jest.resetAllMocks(); - }); - - it('caches mid prices for all markets', async () => { - const market1 = testConstants.defaultPerpetualMarket; - const market2 = testConstants.defaultPerpetualMarket2; - - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockResolvedValueOnce('100.5'); // For market1 - mockGetOrderBookMidPrice.mockResolvedValueOnce('200.75'); // For market2 - - await runTask(); - - // Check if the mock was called with the correct arguments - expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market1.ticker, redisClient); - expect(mockGetOrderBookMidPrice).toHaveBeenCalledWith(market2.ticker, redisClient); - - // Check if prices were cached correctly - const price1 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market1.ticker); - const price2 = await OrderbookMidPricesCache.getMedianPrice(redisClient, market2.ticker); - - expect(price1).toBe('100.5'); - expect(price2).toBe('200.75'); - }); - - it('handles undefined prices', async () => { - const market = testConstants.defaultPerpetualMarket; - - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockResolvedValueOnce(undefined); - - await runTask(); - - const price = await OrderbookMidPricesCache.getMedianPrice(redisClient, market.ticker); - expect(price).toBeNull(); - - // Check that a log message was created - expect(jest.requireMock('@dydxprotocol-indexer/base').logger.info).toHaveBeenCalledWith({ - at: 'cache-orderbook-mid-prices#runTask', - message: `undefined price for ${market.ticker}`, - }); - }); - - it('handles errors', async () => { - // Mock OrderbookLevelsCache.getOrderBookMidPrice to throw an error - const mockGetOrderBookMidPrice = jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice'); - mockGetOrderBookMidPrice.mockRejectedValueOnce(new Error('Test error')); - - await runTask(); - - expect(jest.requireMock('@dydxprotocol-indexer/base').logger.error).toHaveBeenCalledWith({ - at: 'cache-orderbook-mid-prices#runTask', - message: 'Test error', - error: expect.any(Error), - }); - }); -}); diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 34dafba44b..bdc8877e5c 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -60,7 +60,6 @@ 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_CACHE_ORDERBOOK_MID_PRICES: parseBoolean({ default: true }), // Loop Timing LOOPS_INTERVAL_MS_MARKET_UPDATER: parseInteger({ diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index bfdee334c7..f52903ac19 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -10,7 +10,6 @@ import { connect as connectToRedis, } from './helpers/redis'; import aggregateTradingRewardsTasks from './tasks/aggregate-trading-rewards'; -import cacheOrderbookMidPrices from './tasks/cache-orderbook-mid-prices'; import cancelStaleOrdersTask from './tasks/cancel-stale-orders'; import createLeaderboardTask from './tasks/create-leaderboard'; import createPnlTicksTask from './tasks/create-pnl-ticks'; @@ -273,14 +272,6 @@ async function start(): Promise { ); } - if (config.LOOPS_ENABLED_CACHE_ORDERBOOK_MID_PRICES) { - startLoop( - cacheOrderbookMidPrices, - 'cache_orderbook_mid_prices', - config.LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES, - ); - } - logger.info({ at: 'index', message: 'Successfully started', diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts deleted file mode 100644 index 644f50df6f..0000000000 --- a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - logger, -} from '@dydxprotocol-indexer/base'; -import { - PerpetualMarketFromDatabase, - PerpetualMarketTable, -} from '@dydxprotocol-indexer/postgres'; -import { - OrderbookMidPricesCache, - OrderbookLevelsCache, -} from '@dydxprotocol-indexer/redis'; - -import { redisClient } from '../helpers/redis'; - -/** - * Updates OrderbookMidPricesCache with current orderbook mid price for each market - */ -export default async function runTask(): Promise { - const markets: PerpetualMarketFromDatabase[] = await PerpetualMarketTable.findAll({}, []); - - for (const market of markets) { - try { - const price = await OrderbookLevelsCache.getOrderBookMidPrice(market.ticker, redisClient); - if (price) { - await OrderbookMidPricesCache.setPrice(redisClient, market.ticker, price); - } else { - logger.info({ - at: 'cache-orderbook-mid-prices#runTask', - message: `undefined price for ${market.ticker}`, - }); - } - } catch (error) { - logger.error({ - at: 'cache-orderbook-mid-prices#runTask', - message: error.message, - error, - }); - } - } -} From ec8b9195ab9d5d9c70ce57667114e48f2bfc0235 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 09:44:33 -0400 Subject: [PATCH 029/120] Add config var to exclude specific stateful order ids from being processed. (backport #2513) (#2514) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- ...onditional-order-placement-handler.test.ts | 22 ++++++++++ ...onditional-order-triggered-handler.test.ts | 40 +++++++++++++++++++ .../stateful-order-placement-handler.test.ts | 26 ++++++++++++ .../stateful-order-removal-handler.test.ts | 35 ++++++++++++++++ indexer/services/ender/src/config.ts | 8 ++++ .../services/ender/src/lib/block-processor.ts | 20 +++++++++- indexer/services/ender/src/lib/types.ts | 2 + .../dydx_block_processor_ordered_handlers.sql | 2 + ...ydx_block_processor_unordered_handlers.sql | 2 + .../validators/stateful-order-validator.ts | 38 ++++++++++++++++++ .../ender/src/validators/validator.ts | 9 +++++ 11 files changed, 202 insertions(+), 2 deletions(-) diff --git a/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-placement-handler.test.ts b/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-placement-handler.test.ts index edc47dfd76..ca5fb27041 100644 --- a/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-placement-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-placement-handler.test.ts @@ -44,8 +44,11 @@ import Long from 'long'; import { producer } from '@dydxprotocol-indexer/kafka'; import { ConditionalOrderPlacementHandler } from '../../../src/handlers/stateful-order/conditional-order-placement-handler'; import { createPostgresFunctions } from '../../../src/helpers/postgres/postgres-functions'; +import config from '../../../src/config'; describe('conditionalOrderPlacementHandler', () => { + const prevSkippedOrderUUIDs: string = config.SKIP_STATEFUL_ORDER_UUIDS; + beforeAll(async () => { await dbHelpers.migrate(); await createPostgresFunctions(); @@ -59,6 +62,7 @@ describe('conditionalOrderPlacementHandler', () => { }); afterEach(async () => { + config.SKIP_STATEFUL_ORDER_UUIDS = prevSkippedOrderUUIDs; await dbHelpers.clearData(); jest.clearAllMocks(); }); @@ -226,4 +230,22 @@ describe('conditionalOrderPlacementHandler', () => { order!, ); }); + + it.each([ + ['transaction event', 0], + ['block event', -1], + ])('successfully skips order (as %s)', async ( + _name: string, + transactionIndex: number, + ) => { + config.SKIP_STATEFUL_ORDER_UUIDS = OrderTable.orderIdToUuid(defaultOrder.orderId!); + const kafkaMessage: KafkaMessage = createKafkaMessageFromStatefulOrderEvent( + defaultStatefulOrderEvent, + transactionIndex, + ); + + await onMessage(kafkaMessage); + const order: OrderFromDatabase | undefined = await OrderTable.findById(orderId); + expect(order).toBeUndefined(); + }); }); diff --git a/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-triggered-handler.test.ts b/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-triggered-handler.test.ts index cb5ad98721..9e17cbe521 100644 --- a/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-triggered-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-triggered-handler.test.ts @@ -38,8 +38,11 @@ import { ORDER_FLAG_CONDITIONAL } from '@dydxprotocol-indexer/v4-proto-parser'; import { ConditionalOrderTriggeredHandler } from '../../../src/handlers/stateful-order/conditional-order-triggered-handler'; import { defaultPerpetualMarket } from '@dydxprotocol-indexer/postgres/build/__tests__/helpers/constants'; import { createPostgresFunctions } from '../../../src/helpers/postgres/postgres-functions'; +import config from '../../../src/config'; describe('conditionalOrderTriggeredHandler', () => { + const prevSkippedOrderUUIDs: string = config.SKIP_STATEFUL_ORDER_UUIDS; + beforeAll(async () => { await dbHelpers.migrate(); await createPostgresFunctions(); @@ -53,6 +56,7 @@ describe('conditionalOrderTriggeredHandler', () => { }); afterEach(async () => { + config.SKIP_STATEFUL_ORDER_UUIDS = prevSkippedOrderUUIDs; await dbHelpers.clearData(); jest.clearAllMocks(); }); @@ -163,4 +167,40 @@ describe('conditionalOrderTriggeredHandler', () => { `Unable to update order status with orderId: ${orderId}`, ); }); + + it.each([ + ['transaction event', 0], + ['block event', -1], + ])('successfully skips order trigger event (as %s)', async ( + _name: string, + transactionIndex: number, + ) => { + config.SKIP_STATEFUL_ORDER_UUIDS = OrderTable.uuid( + testConstants.defaultOrderGoodTilBlockTime.subaccountId, + '0', + testConstants.defaultOrderGoodTilBlockTime.clobPairId, + testConstants.defaultOrderGoodTilBlockTime.orderFlags, + ); + await OrderTable.create({ + ...testConstants.defaultOrderGoodTilBlockTime, + orderFlags: conditionalOrderId.orderFlags.toString(), + status: OrderStatus.UNTRIGGERED, + triggerPrice: '1000', + clientId: '0', + }); + const kafkaMessage: KafkaMessage = createKafkaMessageFromStatefulOrderEvent( + defaultStatefulOrderEvent, + transactionIndex, + ); + + await onMessage(kafkaMessage); + const order: OrderFromDatabase | undefined = await OrderTable.findById(orderId); + + expect(order).toBeDefined(); + expect(order).toEqual(expect.objectContaining({ + status: OrderStatus.OPEN, + updatedAt: defaultDateTime.toISO(), + updatedAtHeight: defaultHeight.toString(), + })); + }); }); diff --git a/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-placement-handler.test.ts b/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-placement-handler.test.ts index b65e6fe6f6..daa3a746a1 100644 --- a/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-placement-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-placement-handler.test.ts @@ -44,8 +44,11 @@ import { STATEFUL_ORDER_ORDER_FILL_EVENT_TYPE } from '../../../src/constants'; import { producer } from '@dydxprotocol-indexer/kafka'; import { ORDER_FLAG_LONG_TERM } from '@dydxprotocol-indexer/v4-proto-parser'; import { createPostgresFunctions } from '../../../src/helpers/postgres/postgres-functions'; +import config from '../../../src/config'; describe('statefulOrderPlacementHandler', () => { + const prevSkippedOrderUUIDs: string = config.SKIP_STATEFUL_ORDER_UUIDS; + beforeAll(async () => { await dbHelpers.migrate(); await createPostgresFunctions(); @@ -59,6 +62,7 @@ describe('statefulOrderPlacementHandler', () => { }); afterEach(async () => { + config.SKIP_STATEFUL_ORDER_UUIDS = prevSkippedOrderUUIDs; await dbHelpers.clearData(); jest.clearAllMocks(); }); @@ -250,4 +254,26 @@ describe('statefulOrderPlacementHandler', () => { }); // TODO[IND-20]: Add tests for vulcan messages }); + + it.each([ + // TODO(IND-334): Remove after deprecating StatefulOrderPlacementEvent + ['stateful order placement as txn event', defaultStatefulOrderEvent, 0], + ['stateful long term order placement as txn event', defaultStatefulOrderLongTermEvent, 0], + ['stateful order placement as block event', defaultStatefulOrderEvent, -1], + ['stateful long term order placement as block event', defaultStatefulOrderLongTermEvent, -1], + ])('successfully skips order with %s', async ( + _name: string, + statefulOrderEvent: StatefulOrderEventV1, + transactionIndex: number, + ) => { + config.SKIP_STATEFUL_ORDER_UUIDS = OrderTable.orderIdToUuid(defaultOrder.orderId!); + const kafkaMessage: KafkaMessage = createKafkaMessageFromStatefulOrderEvent( + statefulOrderEvent, + transactionIndex, + ); + + await onMessage(kafkaMessage); + const order: OrderFromDatabase | undefined = await OrderTable.findById(orderId); + expect(order).toBeUndefined(); + }); }); diff --git a/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-removal-handler.test.ts b/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-removal-handler.test.ts index 565b361057..135f745256 100644 --- a/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-removal-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-removal-handler.test.ts @@ -37,8 +37,11 @@ import { StatefulOrderRemovalHandler } from '../../../src/handlers/stateful-orde import { STATEFUL_ORDER_ORDER_FILL_EVENT_TYPE } from '../../../src/constants'; import { producer } from '@dydxprotocol-indexer/kafka'; import { createPostgresFunctions } from '../../../src/helpers/postgres/postgres-functions'; +import config from '../../../src/config'; describe('statefulOrderRemovalHandler', () => { + const prevSkippedOrderUUIDs: string = config.SKIP_STATEFUL_ORDER_UUIDS; + beforeAll(async () => { await dbHelpers.migrate(); await createPostgresFunctions(); @@ -52,6 +55,7 @@ describe('statefulOrderRemovalHandler', () => { }); afterEach(async () => { + config.SKIP_STATEFUL_ORDER_UUIDS = prevSkippedOrderUUIDs; await dbHelpers.clearData(); jest.clearAllMocks(); }); @@ -153,4 +157,35 @@ describe('statefulOrderRemovalHandler', () => { `Unable to update order status with orderId: ${orderId}`, ); }); + + it.each([ + ['transaction event', 0], + ['block event', -1], + ])('successfully skips order removal event (as %s)', async ( + _name: string, + transactionIndex: number, + ) => { + config.SKIP_STATEFUL_ORDER_UUIDS = OrderTable.uuid( + testConstants.defaultOrder.subaccountId, + '0', + testConstants.defaultOrder.clobPairId, + testConstants.defaultOrder.orderFlags, + ); + await OrderTable.create({ + ...testConstants.defaultOrder, + clientId: '0', + }); + const kafkaMessage: KafkaMessage = createKafkaMessageFromStatefulOrderEvent( + defaultStatefulOrderEvent, + transactionIndex, + ); + + await onMessage(kafkaMessage); + const order: OrderFromDatabase | undefined = await OrderTable.findById(orderId); + expect(order).toBeDefined(); + expect(order).toEqual(expect.objectContaining({ + ...testConstants.defaultOrder, + clientId: '0', + })); + }); }); diff --git a/indexer/services/ender/src/config.ts b/indexer/services/ender/src/config.ts index c22122b318..201f7807ee 100644 --- a/indexer/services/ender/src/config.ts +++ b/indexer/services/ender/src/config.ts @@ -6,6 +6,7 @@ import { parseSchema, baseConfigSchema, parseBoolean, + parseString, } from '@dydxprotocol-indexer/base'; import { kafkaConfigSchema, @@ -23,6 +24,13 @@ export const configSchema = { SEND_WEBSOCKET_MESSAGES: parseBoolean({ default: true, }), + // Config var to skip processing stateful order events with specific uuids. + // Order UUIDs should be in a string delimited by commas. + // Only set if invalid order events are being included in a block and preventing ender from + // progressing. + SKIP_STATEFUL_ORDER_UUIDS: parseString({ + default: '', + }), }; export default parseSchema(configSchema); diff --git a/indexer/services/ender/src/lib/block-processor.ts b/indexer/services/ender/src/lib/block-processor.ts index f3ab8ba1e3..6051425b8e 100644 --- a/indexer/services/ender/src/lib/block-processor.ts +++ b/indexer/services/ender/src/lib/block-processor.ts @@ -37,7 +37,7 @@ import { KafkaPublisher } from './kafka-publisher'; import { SyncHandlers, SYNCHRONOUS_SUBTYPES } from './sync-handlers'; import { ConsolidatedKafkaEvent, - DydxIndexerSubtypes, EventMessage, EventProtoWithTypeAndVersion, GroupedEvents, + DydxIndexerSubtypes, EventMessage, EventProtoWithTypeAndVersion, GroupedEvents, SKIPPED_EVENT_SUBTYPE, } from './types'; const TXN_EVENT_SUBTYPE_VERSION_TO_VALIDATOR_MAPPING: Record = { @@ -216,12 +216,28 @@ export class BlockProcessor { ); validator.validate(); this.sqlEventPromises[eventProto.blockEventIndex] = validator.getEventForBlockProcessor(); - const handlers: Handler[] = validator.createHandlers( + let handlers: Handler[] = validator.createHandlers( eventProto.indexerTendermintEvent, this.txId, this.messageReceivedTimestamp, ); + if (validator.shouldExcludeEvent()) { + // If the event should be excluded from being processed, set the subtype to a special value + // for skipped events. + this.block.events[eventProto.blockEventIndex] = { + ...this.block.events[eventProto.blockEventIndex], + subtype: SKIPPED_EVENT_SUBTYPE, + }; + // Set handlers to empty array if event is to be skipped. + handlers = []; + logger.info({ + at: 'onMessage#shouldExcludeEvent', + message: 'Excluded event from processing', + eventProto, + }); + } + _.map(handlers, (handler: Handler) => { if (SYNCHRONOUS_SUBTYPES.includes(eventProto.type as DydxIndexerSubtypes)) { this.syncHandlers.addHandler(eventProto.type, handler); diff --git a/indexer/services/ender/src/lib/types.ts b/indexer/services/ender/src/lib/types.ts index 3150c464fc..b13797bf63 100644 --- a/indexer/services/ender/src/lib/types.ts +++ b/indexer/services/ender/src/lib/types.ts @@ -61,6 +61,8 @@ export enum DydxIndexerSubtypes { UPSERT_VAULT = 'upsert_vault', } +export const SKIPPED_EVENT_SUBTYPE = 'skipped_event'; + // Generic interface used for creating the Handler objects // eslint-disable-next-line @typescript-eslint/no-explicit-any export type EventMessage = any; diff --git a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql index 1a6235d850..8d75ea9fe3 100644 --- a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql +++ b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql @@ -69,6 +69,8 @@ BEGIN rval[i] = dydx_funding_handler(block_height, block_time, event_data, event_index, transaction_index); WHEN '"upsert_vault"'::jsonb THEN rval[i] = dydx_vault_upsert_handler(block_time, event_data); + WHEN '"skipped_event"'::jsonb THEN + rval[i] = jsonb_build_object(); ELSE NULL; END CASE; diff --git a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql index 9c985c79ca..4b82d32b5a 100644 --- a/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql +++ b/indexer/services/ender/src/scripts/handlers/dydx_block_processor_unordered_handlers.sql @@ -67,6 +67,8 @@ BEGIN rval[i] = dydx_trading_rewards_handler(block_height, block_time, event_data, event_index, transaction_index, jsonb_array_element_text(block->'txHashes', transaction_index)); WHEN '"register_affiliate"'::jsonb THEN rval[i] = dydx_register_affiliate_handler(block_height, event_data); + WHEN '"skipped_event"'::jsonb THEN + rval[i] = jsonb_build_object(); ELSE NULL; END CASE; diff --git a/indexer/services/ender/src/validators/stateful-order-validator.ts b/indexer/services/ender/src/validators/stateful-order-validator.ts index 8507fb6ca7..4561c3525b 100644 --- a/indexer/services/ender/src/validators/stateful-order-validator.ts +++ b/indexer/services/ender/src/validators/stateful-order-validator.ts @@ -1,3 +1,4 @@ +import { OrderTable } from '@dydxprotocol-indexer/postgres'; import { ORDER_FLAG_CONDITIONAL, ORDER_FLAG_LONG_TERM } from '@dydxprotocol-indexer/v4-proto-parser'; import { IndexerTendermintEvent, @@ -13,6 +14,7 @@ import { } from '@dydxprotocol-indexer/v4-protos'; import Long from 'long'; +import config from '../config'; import { Handler, HandlerInitializer } from '../handlers/handler'; import { ConditionalOrderPlacementHandler } from '../handlers/stateful-order/conditional-order-placement-handler'; import { ConditionalOrderTriggeredHandler } from '../handlers/stateful-order/conditional-order-triggered-handler'; @@ -233,4 +235,40 @@ export class StatefulOrderValidator extends Validator { return [handler]; } + + /** + * Skip order uuids in config env var. + */ + public shouldExcludeEvent(): boolean { + const orderUUIDsToSkip: string[] = config.SKIP_STATEFUL_ORDER_UUIDS.split(','); + if (orderUUIDsToSkip.length === 0) { + return false; + } + + const orderUUIDStoSkipSet: Set = new Set(orderUUIDsToSkip); + if (orderUUIDStoSkipSet.has(this.getOrderUUId())) { + return true; + } + + return false; + } + + /** + * Gets order uuid for the event being validated. + * Assumes events are valid. + */ + private getOrderUUId(): string { + if (this.event.orderPlace !== undefined) { + return OrderTable.orderIdToUuid(this.event.orderPlace.order!.orderId!); + } else if (this.event.orderRemoval !== undefined) { + return OrderTable.orderIdToUuid(this.event.orderRemoval.removedOrderId!); + } else if (this.event.conditionalOrderPlacement !== undefined) { + return OrderTable.orderIdToUuid(this.event.conditionalOrderPlacement.order!.orderId!); + } else if (this.event.conditionalOrderTriggered !== undefined) { + return OrderTable.orderIdToUuid(this.event.conditionalOrderTriggered.triggeredOrderId!); + } else if (this.event.longTermOrderPlacement !== undefined) { + return OrderTable.orderIdToUuid(this.event.longTermOrderPlacement.order!.orderId!); + } + return ''; + } } diff --git a/indexer/services/ender/src/validators/validator.ts b/indexer/services/ender/src/validators/validator.ts index f9c0a53662..e3235fb96f 100644 --- a/indexer/services/ender/src/validators/validator.ts +++ b/indexer/services/ender/src/validators/validator.ts @@ -58,4 +58,13 @@ export abstract class Validator { txId: number, messageReceivedTimestamp: string, ): Handler[]; + + /** + * Allows aribtrary logic to exclude events from being processed. + * Defaults to no events being excluded. + * @returns + */ + public shouldExcludeEvent(): boolean { + return false; + } } From bba2a123a6b67c222c231895127397d9feea35fa Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:15:09 -0400 Subject: [PATCH 030/120] add wallet when transfer to subaccount (backport #2519) (#2520) Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> --- .../__tests__/handlers/transfer-handler.test.ts | 15 +++++++++++---- .../scripts/handlers/dydx_transfer_handler.sql | 5 +++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts b/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts index 4f7f959070..cd8c7e8005 100644 --- a/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts @@ -311,7 +311,7 @@ describe('transferHandler', () => { expect(wallet).toEqual(defaultWallet); }); - it('creates new deposit for previously non-existent subaccount', async () => { + it('creates new deposit for previously non-existent subaccount (also non-existent recipient wallet)', async () => { const transactionIndex: number = 0; const depositEvent: TransferEventV1 = defaultDepositEvent; @@ -348,16 +348,23 @@ describe('transferHandler', () => { newTransfer, asset, ); - // Confirm the wallet was created - const wallet: WalletFromDatabase | undefined = await WalletTable.findById( + // Confirm the wallet was created for the sender and recipient + const walletSender: WalletFromDatabase | undefined = await WalletTable.findById( defaultWalletAddress, ); + const walletRecipient: WalletFromDatabase | undefined = await WalletTable.findById( + defaultDepositEvent.recipient!.subaccountId!.owner, + ); const newRecipientSubaccount: SubaccountFromDatabase | undefined = await SubaccountTable.findById( defaultRecipientSubaccountId, ); expect(newRecipientSubaccount).toBeDefined(); - expect(wallet).toEqual(defaultWallet); + expect(walletSender).toEqual(defaultWallet); + expect(walletRecipient).toEqual({ + ...defaultWallet, + address: defaultDepositEvent.recipient!.subaccountId!.owner, + }); }); it('creates new withdrawal for existing subaccount', async () => { diff --git a/indexer/services/ender/src/scripts/handlers/dydx_transfer_handler.sql b/indexer/services/ender/src/scripts/handlers/dydx_transfer_handler.sql index 396a0075f8..8e9b251548 100644 --- a/indexer/services/ender/src/scripts/handlers/dydx_transfer_handler.sql +++ b/indexer/services/ender/src/scripts/handlers/dydx_transfer_handler.sql @@ -46,6 +46,11 @@ BEGIN SET "updatedAtHeight" = recipient_subaccount_record."updatedAtHeight", "updatedAt" = recipient_subaccount_record."updatedAt"; + + recipient_wallet_record."address" = event_data->'recipient'->'subaccountId'->>'owner'; + recipient_wallet_record."totalTradingRewards" = '0'; + recipient_wallet_record."totalVolume" = '0'; + INSERT INTO wallets VALUES (recipient_wallet_record.*) ON CONFLICT DO NOTHING; END IF; IF event_data->'sender'->'subaccountId' IS NOT NULL THEN From daddb134173cf236efc4b4a4978d03a472bd3ca6 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 19:31:15 -0400 Subject: [PATCH 031/120] update migration to stop excessive consumption of computation (backport #2521) (#2522) Co-authored-by: Mohammed Affan --- ...1410_change_fills_affiliaterevshare_type.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20240910101410_change_fills_affiliaterevshare_type.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20240910101410_change_fills_affiliaterevshare_type.ts index dd61af5d3b..96d7b48083 100644 --- a/indexer/packages/postgres/src/db/migrations/migration_files/20240910101410_change_fills_affiliaterevshare_type.ts +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20240910101410_change_fills_affiliaterevshare_type.ts @@ -2,15 +2,21 @@ import * as Knex from 'knex'; // No data has been stored added at time of commit export async function up(knex: Knex): Promise { - return knex.schema.alterTable('fills', (table) => { - // decimal('columnName') has is 8,2 precision and scale - // decimal('columnName', null) has variable precision and scale - table.decimal('affiliateRevShare', null).notNullable().defaultTo(0).alter(); + // decimal('columnName') has is 8,2 precision and scale + // decimal('columnName', null) has variable precision and scale + await knex.schema.alterTable('fills', (table) => { + table.dropColumn('affiliateRevShare'); + }); + await knex.schema.alterTable('fills', (table) => { + table.decimal('affiliateRevShare', null).notNullable().defaultTo(0); }); } export async function down(knex: Knex): Promise { - return knex.schema.alterTable('fills', (table) => { - table.string('affiliateRevShare').notNullable().defaultTo('0').alter(); + await knex.schema.alterTable('fills', (table) => { + table.dropColumn('affiliateRevShare'); + }); + await knex.schema.alterTable('fills', (table) => { + table.string('affiliateRevShare').notNullable().defaultTo('0'); }); } From bb809c27b74c4e81c11b6ee674da5901aba7e892 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:00:25 -0400 Subject: [PATCH 032/120] Get funding index maps for vault positions in chunks. (backport #2525) (#2527) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../src/stores/funding-index-updates-table.ts | 2 + indexer/services/comlink/src/config.ts | 1 + .../controllers/api/v4/vault-controller.ts | 104 +++++++++++++++++- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/indexer/packages/postgres/src/stores/funding-index-updates-table.ts b/indexer/packages/postgres/src/stores/funding-index-updates-table.ts index 8ef55a3537..785431ff93 100644 --- a/indexer/packages/postgres/src/stores/funding-index-updates-table.ts +++ b/indexer/packages/postgres/src/stores/funding-index-updates-table.ts @@ -242,6 +242,7 @@ export async function findFundingIndexMaps( .sort(); // Get the min height to limit the search to blocks 4 hours or before the min height. const minHeight: number = heightNumbers[0]; + const maxheight: number = heightNumbers[heightNumbers.length - 1]; const result: { rows: FundingIndexUpdatesFromDatabaseWithSearchHeight[], @@ -255,6 +256,7 @@ export async function findFundingIndexMaps( unnest(ARRAY[${heightNumbers.join(',')}]) AS "searchHeight" WHERE "effectiveAtHeight" > ${Big(minHeight).minus(FOUR_HOUR_OF_BLOCKS).toFixed()} AND + "effectiveAtHeight" <= ${Big(maxheight)} AND "effectiveAtHeight" <= "searchHeight" ORDER BY "perpetualId", diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index 743bae1dd4..bfb702abcc 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -63,6 +63,7 @@ export const configSchema = { VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }), VAULT_PNL_HISTORY_HOURS: parseInteger({ default: 72 }), VAULT_LATEST_PNL_TICK_WINDOW_HOURS: parseInteger({ default: 1 }), + VAULT_FETCH_FUNDING_INDEX_BLOCK_WINDOWS: parseInteger({ default: 250_000 }), }; //////////////////////////////////////////////////////////////////////////////// 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 9480b096f1..e4855b016a 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -1,4 +1,4 @@ -import { stats } from '@dydxprotocol-indexer/base'; +import { logger, stats } from '@dydxprotocol-indexer/base'; import { PnlTicksFromDatabase, PnlTicksTable, @@ -71,7 +71,14 @@ class VaultController extends Controller { async getMegavaultHistoricalPnl( @Query() resolution?: PnlTickInterval, ): Promise { + const start: number = Date.now(); const vaultSubaccounts: VaultMapping = await getVaultMapping(); + stats.timing( + `${config.SERVICE_NAME}.${controllerName}.fetch_vaults.timing`, + Date.now() - start, + ); + + const startTicksPositions: number = Date.now(); const vaultSubaccountIdsWithMainSubaccount: string[] = _ .keys(vaultSubaccounts) .concat([MEGAVAULT_SUBACCOUNT_ID]); @@ -94,6 +101,10 @@ class VaultController extends Controller { getMainSubaccountEquity(), getLatestPnlTick(vaultSubaccountIdsWithMainSubaccount), ]); + stats.timing( + `${config.SERVICE_NAME}.${controllerName}.fetch_ticks_positions_equity.timing`, + Date.now() - startTicksPositions, + ); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(vaultPnlTicks); @@ -324,6 +335,7 @@ async function getVaultSubaccountPnlTicks( async function getVaultPositions( vaultSubaccounts: VaultMapping, ): Promise> { + const start: number = Date.now(); const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts); if (vaultSubaccountIds.length === 0) { return new Map(); @@ -374,7 +386,12 @@ async function getVaultPositions( ), BlockTable.getLatest(), ]); + stats.timing( + `${config.SERVICE_NAME}.${controllerName}.positions.fetch_subaccounts_positions.timing`, + Date.now() - start, + ); + const startFunding: number = Date.now(); const updatedAtHeights: string[] = _(subaccounts).map('updatedAtHeight').uniq().value(); const [ latestFundingIndexMap, @@ -387,11 +404,13 @@ async function getVaultPositions( .findFundingIndexMap( latestBlock.blockHeight, ), - FundingIndexUpdatesTable - .findFundingIndexMaps( - updatedAtHeights, - ), + getFundingIndexMapsChunked(updatedAtHeights), ]); + stats.timing( + `${config.SERVICE_NAME}.${controllerName}.positions.fetch_funding.timing`, + Date.now() - startFunding, + ); + const assetPositionsBySubaccount: { [subaccountId: string]: AssetPositionFromDatabase[] } = _.groupBy( assetPositions, @@ -557,13 +576,68 @@ function getResolution(resolution: PnlTickInterval = PnlTickInterval.day): PnlTi return resolution; } +/** + * Gets funding index maps in a chunked fashion to reduce database load and aggregates into a + * a map of funding index maps. + * @param updatedAtHeights + * @returns + */ +async function getFundingIndexMapsChunked( + updatedAtHeights: string[], +): Promise<{[blockHeight: string]: FundingIndexMap}> { + const updatedAtHeightsNum: number[] = updatedAtHeights.map((height: string): number => { + return parseInt(height, 10); + }).sort(); + const aggregateFundingIndexMaps: {[blockHeight: string]: FundingIndexMap} = {}; + await Promise.all(getHeightWindows(updatedAtHeightsNum).map( + async (heightWindow: number[]): Promise => { + const fundingIndexMaps: {[blockHeight: string]: FundingIndexMap} = await + FundingIndexUpdatesTable + .findFundingIndexMaps( + heightWindow.map((heightNum: number): string => { return heightNum.toString(); }), + ); + for (const height of _.keys(fundingIndexMaps)) { + aggregateFundingIndexMaps[height] = fundingIndexMaps[height]; + } + })); + return aggregateFundingIndexMaps; +} + +/** + * Separates an array of heights into a chunks based on a window size. Each chunk should only + * contain heights within a certain number of blocks of each other. + * @param heights + * @returns + */ +function getHeightWindows( + heights: number[], +): number[][] { + if (heights.length === 0) { + return []; + } + const windows: number[][] = []; + let windowStart: number = heights[0]; + let currentWindow: number[] = []; + for (const height of heights) { + if (height - windowStart < config.VAULT_FETCH_FUNDING_INDEX_BLOCK_WINDOWS) { + currentWindow.push(height); + } else { + windows.push(currentWindow); + currentWindow = [height]; + windowStart = height; + } + } + windows.push(currentWindow); + return windows; +} + async function getVaultMapping(): Promise { const vaults: VaultFromDatabase[] = await VaultTable.findAll( {}, [], {}, ); - return _.zipObject( + const vaultMapping: VaultMapping = _.zipObject( vaults.map((vault: VaultFromDatabase): string => { return SubaccountTable.uuid(vault.address, 0); }), @@ -571,6 +645,24 @@ async function getVaultMapping(): Promise { return vault.clobPairId; }), ); + const validVaultMapping: VaultMapping = {}; + for (const subaccountId of _.keys(vaultMapping)) { + const perpetual: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher + .getPerpetualMarketFromClobPairId( + vaultMapping[subaccountId], + ); + if (perpetual === undefined) { + logger.warning({ + at: 'VaultController#getVaultPositions', + message: `Vault clob pair id ${vaultMapping[subaccountId]} does not correspond to a ` + + 'perpetual market.', + subaccountId, + }); + continue; + } + validVaultMapping[subaccountId] = vaultMapping[subaccountId]; + } + return vaultMapping; } export default router; From 32cbd9d9a5ab0c5f03d7d29ab6c1387f23919ed5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:16:35 -0400 Subject: [PATCH 033/120] Vulcan topic to 210 partitions (backport #2528) (#2530) Co-authored-by: roy-dydx <133032749+roy-dydx@users.noreply.github.com> --- indexer/services/bazooka/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indexer/services/bazooka/src/index.ts b/indexer/services/bazooka/src/index.ts index 8329bd69a0..efd30af255 100644 --- a/indexer/services/bazooka/src/index.ts +++ b/indexer/services/bazooka/src/index.ts @@ -25,7 +25,7 @@ const DEFAULT_NUM_REPLICAS: number = 3; const KAFKA_TOPICS_TO_PARTITIONS: { [key in KafkaTopics]: number } = { [KafkaTopics.TO_ENDER]: 1, - [KafkaTopics.TO_VULCAN]: 150, + [KafkaTopics.TO_VULCAN]: 210, [KafkaTopics.TO_WEBSOCKETS_ORDERBOOKS]: 1, [KafkaTopics.TO_WEBSOCKETS_SUBACCOUNTS]: 3, [KafkaTopics.TO_WEBSOCKETS_TRADES]: 1, From 38a2d36d80f344bb197a4f9637c664be68175b31 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:36:44 -0400 Subject: [PATCH 034/120] Fix typo and add test for invalid vaults. (backport #2535) (#2536) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../__tests__/controllers/api/v4/vault-controller.test.ts | 7 ++++++- .../comlink/src/controllers/api/v4/vault-controller.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) 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 582cb25361..1686311cc1 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 @@ -451,7 +451,7 @@ describe('vault-controller#V4', () => { }); }); - it('Get /megavault/positions with 2 vault subaccount, 1 with no perpetual', async () => { + it('Get /megavault/positions with 2 vault subaccount, 1 with no perpetual, 1 invalid', async () => { await Promise.all([ VaultTable.create({ ...testConstants.defaultVault, @@ -463,6 +463,11 @@ describe('vault-controller#V4', () => { address: testConstants.vaultAddress, clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, }), + VaultTable.create({ + ...testConstants.defaultVault, + address: 'invalid', + clobPairId: '999', + }), ]); const response: request.Response = await sendRequest({ type: RequestMethod.GET, 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 e4855b016a..10342c28e4 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -662,7 +662,7 @@ async function getVaultMapping(): Promise { } validVaultMapping[subaccountId] = vaultMapping[subaccountId]; } - return vaultMapping; + return validVaultMapping; } export default router; From c49f48e20c76dcd14b9d5f686efca1322194ee76 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 27 Oct 2024 22:11:12 -0400 Subject: [PATCH 035/120] Add missing fields to perpetual markets kafka update (backport #2539) (#2542) Co-authored-by: shrenujb <98204323+shrenujb@users.noreply.github.com> --- .../postgres/src/types/websocket-message-types.ts | 4 ++++ indexer/services/ender/src/helpers/kafka-helper.ts | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/indexer/packages/postgres/src/types/websocket-message-types.ts b/indexer/packages/postgres/src/types/websocket-message-types.ts index 1d1cd6d607..4f5f812250 100644 --- a/indexer/packages/postgres/src/types/websocket-message-types.ts +++ b/indexer/packages/postgres/src/types/websocket-message-types.ts @@ -223,6 +223,10 @@ export interface TradingPerpetualMarketMessage { volume24H?: string, trades24H?: number, nextFundingRate?: string, + + // Derived fields + tickSize?: string, + stepSize?: string, } export type OraclePriceMarketMessageContentsMapping = { diff --git a/indexer/services/ender/src/helpers/kafka-helper.ts b/indexer/services/ender/src/helpers/kafka-helper.ts index 2fd50a1c4a..db88bdac28 100644 --- a/indexer/services/ender/src/helpers/kafka-helper.ts +++ b/indexer/services/ender/src/helpers/kafka-helper.ts @@ -21,6 +21,7 @@ import { PerpetualPositionFromDatabase, PerpetualPositionSubaccountMessageContents, PositionSide, + protocolTranslations, SubaccountMessageContents, SubaccountTable, TradingMarketMessageContents, @@ -328,6 +329,7 @@ export function generatePerpetualMarketMessage( atomicResolution: perpetualMarket.atomicResolution, subticksPerTick: perpetualMarket.subticksPerTick, stepBaseQuantums: perpetualMarket.stepBaseQuantums, + marketType: perpetualMarket.marketType, initialMarginFraction: helpers.ppmToString(Number(liquidityTier.initialMarginPpm)), maintenanceMarginFraction: helpers.ppmToString( helpers.getMaintenanceMarginPpm( @@ -337,6 +339,14 @@ export function generatePerpetualMarketMessage( ), openInterestLowerCap: liquidityTier.openInterestLowerCap, openInterestUpperCap: liquidityTier.openInterestUpperCap, + tickSize: protocolTranslations.getTickSize(perpetualMarket), + stepSize: protocolTranslations.getStepSize(perpetualMarket), + priceChange24H: perpetualMarket.priceChange24H, + volume24H: perpetualMarket.volume24H, + trades24H: perpetualMarket.trades24H, + nextFundingRate: perpetualMarket.nextFundingRate, + openInterest: perpetualMarket.openInterest, + baseOpenInterest: perpetualMarket.baseOpenInterest, }; }) .value(); From c4348fb09b012991c490a450e165dd752aa369ce Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:52:05 -0400 Subject: [PATCH 036/120] De-duplicate and filter out invalid pnl ticks for megavault. (backport #2540) (#2545) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- indexer/pnpm-lock.yaml | 6 ++ .../api/v4/vault-controller.test.ts | 19 +++- .../comlink/__tests__/lib/helpers.test.ts | 70 +++++++++---- indexer/services/comlink/package.json | 3 +- .../api/v4/historical-pnl-controller.ts | 6 +- .../controllers/api/v4/vault-controller.ts | 97 ++++++++++++++++--- indexer/services/comlink/src/lib/helpers.ts | 20 +++- indexer/services/comlink/src/types.ts | 5 + 8 files changed, 187 insertions(+), 39 deletions(-) diff --git a/indexer/pnpm-lock.yaml b/indexer/pnpm-lock.yaml index 3f7362293d..0b961578cc 100644 --- a/indexer/pnpm-lock.yaml +++ b/indexer/pnpm-lock.yaml @@ -471,6 +471,7 @@ importers: '@types/supertest': ^2.0.12 '@types/swagger-ui-express': ^4.1.3 big.js: ^6.2.1 + binary-searching: ^2.0.5 body-parser: ^1.20.0 concurrently: ^7.6.0 cors: ^2.8.5 @@ -510,6 +511,7 @@ importers: '@keplr-wallet/cosmos': 0.12.122 '@tsoa/runtime': 5.0.0 big.js: 6.2.1 + binary-searching: 2.0.5 body-parser: 1.20.0 cors: 2.8.5 dd-trace: 3.32.1 @@ -7939,6 +7941,10 @@ packages: resolution: {integrity: sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==} dev: false + /binary-searching/2.0.5: + resolution: {integrity: sha512-v4N2l3RxL+m4zDxyxz3Ne2aTmiPn8ZUpKFpdPtO+ItW1NcTCXA7JeHG5GMBSvoKSkQZ9ycS+EouDVxYB9ufKWA==} + dev: false + /bindings/1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} dependencies: 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 1686311cc1..960e5c57b6 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 @@ -15,6 +15,7 @@ import { VaultTable, MEGAVAULT_MODULE_ADDRESS, MEGAVAULT_SUBACCOUNT_ID, + TransferTable, } from '@dydxprotocol-indexer/postgres'; import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; import request from 'supertest'; @@ -181,11 +182,12 @@ describe('vault-controller#V4', () => { [ 'hourly resolution', '?resolution=hour', - [1, undefined, 2, 3, 4], - [undefined, 6, 7, 8, 9], - [11, undefined, 12, 13, 14], + [1, 2, 3, 4], + [undefined, 7, 8, 9], + [11, 12, 13, 14], ], - ])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async ( + ])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s), ' + + 'excludes tick with missing vault ticks', async ( _name: string, queryParam: string, expectedTicksIndex1: (number | undefined)[], @@ -202,16 +204,24 @@ describe('vault-controller#V4', () => { ...testConstants.defaultVault, address: testConstants.defaultAddress, clobPairId: testConstants.defaultPerpetualMarket.clobPairId, + createdAt: twoDaysAgo.toISO(), }), + // Single tick for this vault will be excluded from result. VaultTable.create({ ...testConstants.defaultVault, address: testConstants.vaultAddress, clobPairId: testConstants.defaultPerpetualMarket2.clobPairId, + createdAt: almostTwoDaysAgo.toISO(), }), AssetPositionTable.upsert({ ...testConstants.defaultAssetPosition, subaccountId: MEGAVAULT_SUBACCOUNT_ID, }), + TransferTable.create({ + ...testConstants.defaultTransfer, + recipientSubaccountId: MEGAVAULT_SUBACCOUNT_ID, + createdAt: twoDaysAgo.toISO(), + }), ]); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks( @@ -559,6 +569,7 @@ describe('vault-controller#V4', () => { ...testConstants.defaultPnlTick, subaccountId: testConstants.vaultSubaccountId, }), + // Invalid pnl tick to be excluded as only a single pnl tick but 2 pnl ticks should exist. PnlTicksTable.create({ ...testConstants.defaultPnlTick, subaccountId: testConstants.vaultSubaccountId, diff --git a/indexer/services/comlink/__tests__/lib/helpers.test.ts b/indexer/services/comlink/__tests__/lib/helpers.test.ts index d814827235..03d169db35 100644 --- a/indexer/services/comlink/__tests__/lib/helpers.test.ts +++ b/indexer/services/comlink/__tests__/lib/helpers.test.ts @@ -58,7 +58,9 @@ import { defaultTendermintEventId2, defaultTendermintEventId3, } from '@dydxprotocol-indexer/postgres/build/__tests__/helpers/constants'; -import { AssetPositionsMap, PerpetualPositionWithFunding, SubaccountResponseObject } from '../../src/types'; +import { + AggregatedPnlTick, AssetPositionsMap, PerpetualPositionWithFunding, SubaccountResponseObject, +} from '../../src/types'; import { ZERO, ZERO_USDC_POSITION } from '../../src/lib/constants'; import { DateTime } from 'luxon'; @@ -844,15 +846,20 @@ describe('helpers', () => { ), }; - const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks([pnlTick]); + const aggregatedPnlTicks: AggregatedPnlTick[] = aggregateHourlyPnlTicks([pnlTick]); expect( aggregatedPnlTicks, ).toEqual( - [expect.objectContaining({ ...testConstants.defaultPnlTick })], + [expect.objectContaining( + { + pnlTick: expect.objectContaining(testConstants.defaultPnlTick), + numTicks: 1, + }, + )], ); }); - it('aggregates multiple pnl ticks same height', () => { + it('aggregates multiple pnl ticks same height and de-dupes ticks', () => { const pnlTick: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, id: PnlTicksTable.uuid( @@ -862,6 +869,7 @@ describe('helpers', () => { }; const pnlTick2: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, + subaccountId: testConstants.defaultSubaccountId2, id: PnlTicksTable.uuid( testConstants.defaultSubaccountId2, testConstants.defaultPnlTick.createdAt, @@ -883,8 +891,9 @@ describe('helpers', () => { const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).plus({ minute: 61 }).toISO(); const pnlTick4: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, + subaccountId: testConstants.defaultSubaccountId2, id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, + testConstants.defaultSubaccountId2, blockTime3, ), equity: '1', @@ -894,29 +903,52 @@ describe('helpers', () => { blockTime: blockTime3, createdAt: blockTime3, }; + const blockHeight4: string = '82'; + const blockTime4: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').plus({ minute: 63 }).toISO(); + // should be de-duped + const pnlTick5: PnlTicksFromDatabase = { + ...testConstants.defaultPnlTick, + subaccountId: testConstants.defaultSubaccountId2, + id: PnlTicksTable.uuid( + testConstants.defaultSubaccountId2, + blockTime4, + ), + equity: '1', + totalPnl: '2', + netTransfers: '3', + blockHeight: blockHeight4, + blockTime: blockTime4, + createdAt: blockTime4, + }; - const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks( - [pnlTick, pnlTick2, pnlTick3, pnlTick4], + const aggregatedPnlTicks: AggregatedPnlTick[] = aggregateHourlyPnlTicks( + [pnlTick, pnlTick2, pnlTick3, pnlTick4, pnlTick5], ); expect(aggregatedPnlTicks).toEqual( expect.arrayContaining([ // Combined pnl tick at initial hour expect.objectContaining({ - equity: (parseFloat(testConstants.defaultPnlTick.equity) + - parseFloat(pnlTick2.equity)).toString(), - totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) + - parseFloat(pnlTick2.totalPnl)).toString(), - netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) + - parseFloat(pnlTick2.netTransfers)).toString(), + pnlTick: expect.objectContaining({ + equity: (parseFloat(testConstants.defaultPnlTick.equity) + + parseFloat(pnlTick2.equity)).toString(), + totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) + + parseFloat(pnlTick2.totalPnl)).toString(), + netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) + + parseFloat(pnlTick2.netTransfers)).toString(), + }), + numTicks: 2, }), // Combined pnl tick at initial hour + 1 hour and initial hour + 1 hour, 1 minute expect.objectContaining({ - equity: (parseFloat(pnlTick3.equity) + - parseFloat(pnlTick4.equity)).toString(), - totalPnl: (parseFloat(pnlTick3.totalPnl) + - parseFloat(pnlTick4.totalPnl)).toString(), - netTransfers: (parseFloat(pnlTick3.netTransfers) + - parseFloat(pnlTick4.netTransfers)).toString(), + pnlTick: expect.objectContaining({ + equity: (parseFloat(pnlTick3.equity) + + parseFloat(pnlTick4.equity)).toString(), + totalPnl: (parseFloat(pnlTick3.totalPnl) + + parseFloat(pnlTick4.totalPnl)).toString(), + netTransfers: (parseFloat(pnlTick3.netTransfers) + + parseFloat(pnlTick4.netTransfers)).toString(), + }), + numTicks: 2, }), ]), ); diff --git a/indexer/services/comlink/package.json b/indexer/services/comlink/package.json index 29ea1def60..b4ac31ae38 100644 --- a/indexer/services/comlink/package.json +++ b/indexer/services/comlink/package.json @@ -28,14 +28,15 @@ "@cosmjs/encoding": "^0.32.3", "@dydxprotocol-indexer/base": "workspace:^0.0.1", "@dydxprotocol-indexer/compliance": "workspace:^0.0.1", + "@dydxprotocol-indexer/notifications": "workspace:^0.0.1", "@dydxprotocol-indexer/postgres": "workspace:^0.0.1", "@dydxprotocol-indexer/redis": "workspace:^0.0.1", "@dydxprotocol-indexer/v4-proto-parser": "workspace:^0.0.1", "@dydxprotocol-indexer/v4-protos": "workspace:^0.0.1", "@keplr-wallet/cosmos": "^0.12.122", - "@dydxprotocol-indexer/notifications": "workspace:^0.0.1", "@tsoa/runtime": "^5.0.0", "big.js": "^6.2.1", + "binary-searching": "^2.0.5", "body-parser": "^1.20.0", "cors": "^2.8.5", "dd-trace": "^3.32.1", diff --git a/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts b/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts index 96a3131ea9..a1682eec94 100644 --- a/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/historical-pnl-controller.ts @@ -11,6 +11,7 @@ import { } from '@dydxprotocol-indexer/postgres'; import express from 'express'; import { matchedData } from 'express-validator'; +import _ from 'lodash'; import { Controller, Get, Query, Route, } from 'tsoa'; @@ -156,7 +157,10 @@ class HistoricalPnlController extends Controller { } // aggregate pnlTicks for all subaccounts grouped by blockHeight - const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(pnlTicks); + const aggregatedPnlTicks: PnlTicksFromDatabase[] = _.map( + aggregateHourlyPnlTicks(pnlTicks), + 'pnlTick', + ); return { historicalPnl: aggregatedPnlTicks.map( 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 10342c28e4..a249b50b23 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -25,8 +25,13 @@ import { VaultTable, VaultFromDatabase, MEGAVAULT_SUBACCOUNT_ID, + TransferFromDatabase, + TransferTable, + TransferColumns, + Ordering, } from '@dydxprotocol-indexer/postgres'; import Big from 'big.js'; +import bounds from 'binary-searching'; import express from 'express'; import { checkSchema, matchedData } from 'express-validator'; import _ from 'lodash'; @@ -56,13 +61,14 @@ import { SubaccountResponseObject, MegavaultHistoricalPnlRequest, VaultsHistoricalPnlRequest, + AggregatedPnlTick, } from '../../../types'; const router: express.Router = express.Router(); const controllerName: string = 'vault-controller'; interface VaultMapping { - [subaccountId: string]: string, + [subaccountId: string]: VaultFromDatabase, } @Route('vault/v1') @@ -88,18 +94,21 @@ class VaultController extends Controller { latestBlock, mainSubaccountEquity, latestPnlTick, + firstMainVaultTransferTimestamp, ] : [ PnlTicksFromDatabase[], Map, BlockFromDatabase, string, PnlTicksFromDatabase | undefined, + DateTime | undefined ] = await Promise.all([ getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, getResolution(resolution)), getVaultPositions(vaultSubaccounts), BlockTable.getLatest(), getMainSubaccountEquity(), - getLatestPnlTick(vaultSubaccountIdsWithMainSubaccount), + getLatestPnlTick(vaultSubaccountIdsWithMainSubaccount, _.values(vaultSubaccounts)), + getFirstMainVaultTransferDateTime(), ]); stats.timing( `${config.SERVICE_NAME}.${controllerName}.fetch_ticks_positions_equity.timing`, @@ -107,7 +116,11 @@ class VaultController extends Controller { ); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight - const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(vaultPnlTicks); + const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateVaultPnlTicks( + vaultPnlTicks, + _.values(vaultSubaccounts), + firstMainVaultTransferTimestamp, + ); const currentEquity: string = Array.from(vaultPositions.values()) .map((position: VaultPosition): string => { @@ -154,7 +167,7 @@ class VaultController extends Controller { .mapValues((pnlTicks: PnlTicksFromDatabase[], subaccountId: string): VaultHistoricalPnl => { const market: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher .getPerpetualMarketFromClobPairId( - vaultSubaccounts[subaccountId], + vaultSubaccounts[subaccountId].clobPairId, ); if (market === undefined) { @@ -306,7 +319,8 @@ router.get( Date.now() - start, ); } - }); + }, +); async function getVaultSubaccountPnlTicks( vaultSubaccountIds: string[], @@ -431,7 +445,7 @@ async function getVaultPositions( subaccountId: string, }[] = subaccounts.map((subaccount: SubaccountFromDatabase) => { const perpetualMarket: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher - .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id]); + .getPerpetualMarketFromClobPairId(vaultSubaccounts[subaccount.id].clobPairId); if (perpetualMarket === undefined) { throw new Error( `Vault clob pair id ${vaultSubaccounts[subaccount.id]} does not correspond to a ` + @@ -522,6 +536,7 @@ function getPnlTicksWithCurrentTick( export async function getLatestPnlTick( vaultSubaccountIds: string[], + vaults: VaultFromDatabase[], ): Promise { const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( PnlTickInterval.hour, @@ -529,7 +544,10 @@ export async function getLatestPnlTick( vaultSubaccountIds, ); // Aggregate and get pnl tick closest to the hour - const aggregatedTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(pnlTicks); + const aggregatedTicks: PnlTicksFromDatabase[] = aggregateVaultPnlTicks( + pnlTicks, + vaults, + ); const filteredTicks: PnlTicksFromDatabase[] = filterOutIntervalTicks( aggregatedTicks, PnlTickInterval.hour, @@ -631,6 +649,65 @@ function getHeightWindows( return windows; } +async function getFirstMainVaultTransferDateTime(): Promise { + const { results }: { + results: TransferFromDatabase[], + } = await TransferTable.findAllToOrFromSubaccountId( + { + subaccountId: [MEGAVAULT_SUBACCOUNT_ID], + limit: 1, + }, + [], + { + orderBy: [[TransferColumns.createdAt, Ordering.ASC]], + }, + ); + if (results.length === 0) { + return undefined; + } + return DateTime.fromISO(results[0].createdAt); +} + +/** + * Aggregates vault pnl ticks per hour, filtering out pnl ticks made up of less ticks than expected. + * Expected number of pnl ticks is calculated from the number of vaults that were created before + * the pnl tick was created. + * @param vaultPnlTicks Pnl ticks to aggregate. + * @param vaults List of all valid vaults. + * @param mainVaultCreatedAt Date time when the main vault was created or undefined if it does not + * exist yet. + * @returns + */ +function aggregateVaultPnlTicks( + vaultPnlTicks: PnlTicksFromDatabase[], + vaults: VaultFromDatabase[], + mainVaultCreatedAt?: DateTime, +): PnlTicksFromDatabase[] { + // aggregate pnlTicks for all vault subaccounts grouped by blockHeight + const aggregatedPnlTicks: AggregatedPnlTick[] = aggregateHourlyPnlTicks(vaultPnlTicks); + const vaultCreationTimes: DateTime[] = _.map(vaults, 'createdAt').map( + (createdAt: string) => { return DateTime.fromISO(createdAt); }, + ).concat( + mainVaultCreatedAt === undefined ? [] : [mainVaultCreatedAt], + ).sort( + (a: DateTime, b: DateTime) => { + return a.diff(b).milliseconds; + }, + ); + return aggregatedPnlTicks.filter((aggregatedTick: AggregatedPnlTick) => { + // Get number of vaults created before the pnl tick was created by binary-searching for the + // index of the pnl ticks createdAt in a sorted array of vault createdAt times. + const numVaultsCreated: number = bounds.le( + vaultCreationTimes, + DateTime.fromISO(aggregatedTick.pnlTick.createdAt), + (a: DateTime, b: DateTime) => { return a.diff(b).milliseconds; }, + ); + // Number of ticks should be greater than number of vaults created before it as there should be + // a tick for the main vault subaccount. + return aggregatedTick.numTicks >= numVaultsCreated; + }).map((aggregatedPnlTick: AggregatedPnlTick) => { return aggregatedPnlTick.pnlTick; }); +} + async function getVaultMapping(): Promise { const vaults: VaultFromDatabase[] = await VaultTable.findAll( {}, @@ -641,15 +718,13 @@ async function getVaultMapping(): Promise { vaults.map((vault: VaultFromDatabase): string => { return SubaccountTable.uuid(vault.address, 0); }), - vaults.map((vault: VaultFromDatabase): string => { - return vault.clobPairId; - }), + vaults, ); const validVaultMapping: VaultMapping = {}; for (const subaccountId of _.keys(vaultMapping)) { const perpetual: PerpetualMarketFromDatabase | undefined = perpetualMarketRefresher .getPerpetualMarketFromClobPairId( - vaultMapping[subaccountId], + vaultMapping[subaccountId].clobPairId, ); if (perpetual === undefined) { logger.warning({ diff --git a/indexer/services/comlink/src/lib/helpers.ts b/indexer/services/comlink/src/lib/helpers.ts index b3f5d3bf19..16d27bf624 100644 --- a/indexer/services/comlink/src/lib/helpers.ts +++ b/indexer/services/comlink/src/lib/helpers.ts @@ -37,6 +37,7 @@ import { subaccountToResponseObject, } from '../request-helpers/request-transformer'; import { + AggregatedPnlTick, AssetById, AssetPositionResponseObject, AssetPositionsMap, @@ -675,17 +676,23 @@ export function getSubaccountResponse( /** * Aggregates a list of PnL ticks, combining any PnL ticks for the same hour by summing * the equity, totalPnl, and net transfers. - * Returns a map of block height to the resulting PnL tick. + * Returns a map of aggregated pnl ticks and the number of ticks the aggreated tick is made up of. * @param pnlTicks * @returns */ export function aggregateHourlyPnlTicks( pnlTicks: PnlTicksFromDatabase[], -): PnlTicksFromDatabase[] { +): AggregatedPnlTick[] { const hourlyPnlTicks: Map = new Map(); + const hourlySubaccountIds: Map> = new Map(); for (const pnlTick of pnlTicks) { const truncatedTime: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').toISO(); if (hourlyPnlTicks.has(truncatedTime)) { + const subaccountIds: Set = hourlySubaccountIds.get(truncatedTime) as Set; + if (subaccountIds.has(pnlTick.subaccountId)) { + continue; + } + subaccountIds.add(pnlTick.subaccountId); const aggregatedTick: PnlTicksFromDatabase = hourlyPnlTicks.get( truncatedTime, ) as PnlTicksFromDatabase; @@ -700,9 +707,16 @@ export function aggregateHourlyPnlTicks( ).toString(), }, ); + hourlySubaccountIds.set(truncatedTime, subaccountIds); } else { hourlyPnlTicks.set(truncatedTime, pnlTick); + hourlySubaccountIds.set(truncatedTime, new Set([pnlTick.subaccountId])); } } - return Array.from(hourlyPnlTicks.values()); + return Array.from(hourlyPnlTicks.keys()).map((hour: string): AggregatedPnlTick => { + return { + pnlTick: hourlyPnlTicks.get(hour) as PnlTicksFromDatabase, + numTicks: (hourlySubaccountIds.get(hour) as Set).size, + }; + }); } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 0e0a57512c..fc83a92e29 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -264,6 +264,11 @@ export interface PnlTicksResponseObject { blockTime: IsoString, } +export interface AggregatedPnlTick{ + pnlTick: PnlTicksResponseObject, + numTicks: number, +} + /* ------- TRADE TYPES ------- */ export interface TradeResponse extends PaginationResponse { From 86f1b48d77f7c0cadc01b79d9c76e6c7b30d6cd1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:50:40 -0400 Subject: [PATCH 037/120] [CT-1307] Make pnl ticks computation consistent within a transaction. (backport #2548) (#2549) Co-authored-by: vincentwschau <99756290+vincentwschau@users.noreply.github.com> --- .../__tests__/helpers/pnl-ticks-helper.test.ts | 16 ++++++++++------ .../roundtable/src/helpers/pnl-ticks-helper.ts | 10 ++++++++-- .../roundtable/src/tasks/create-pnl-ticks.ts | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/indexer/services/roundtable/__tests__/helpers/pnl-ticks-helper.test.ts b/indexer/services/roundtable/__tests__/helpers/pnl-ticks-helper.test.ts index c60cca50bc..e962c0f077 100644 --- a/indexer/services/roundtable/__tests__/helpers/pnl-ticks-helper.test.ts +++ b/indexer/services/roundtable/__tests__/helpers/pnl-ticks-helper.test.ts @@ -477,6 +477,8 @@ describe('pnl-ticks-helper', () => { it('getNewPnlTicks with prior pnl ticks', async () => { config.PNL_TICK_UPDATE_INTERVAL_MS = 3_600_000; + const blockHeight: string = '5'; + const blockTime: IsoString = DateTime.utc(2022, 6, 2, 0, 30).toISO(); const ticksForSubaccounts: PnlTickForSubaccounts = { [testConstants.defaultSubaccountId]: { ...testConstants.defaultPnlTick, @@ -487,8 +489,6 @@ describe('pnl-ticks-helper', () => { ticksForSubaccounts, redisClient, ); - const blockHeight: string = '5'; - const blockTime: IsoString = DateTime.utc(2022, 6, 2, 0, 30).toISO(); await BlockTable.create({ blockHeight, time: blockTime, @@ -497,7 +497,7 @@ describe('pnl-ticks-helper', () => { const txId: number = await Transaction.start(); jest.spyOn(DateTime, 'utc').mockImplementation(() => dateTime); const newTicksToCreate: PnlTicksCreateObject[] = await - getPnlTicksCreateObjects(blockHeight, blockTime, txId); + getPnlTicksCreateObjects(txId); await Transaction.rollback(txId); expect(newTicksToCreate.length).toEqual(1); expect(newTicksToCreate).toEqual( @@ -517,12 +517,16 @@ describe('pnl-ticks-helper', () => { it('getNewPnlTicks without prior pnl ticks', async () => { jest.spyOn(DateTime, 'utc').mockImplementation(() => dateTime); - await TransferTable.create(testConstants.defaultTransfer); - const txId: number = await Transaction.start(); const blockHeight: string = '5'; const blockTime: IsoString = DateTime.utc(2022, 6, 2, 0, 30).toISO(); + await TransferTable.create(testConstants.defaultTransfer); + await BlockTable.create({ + blockHeight, + time: blockTime, + }); + const txId: number = await Transaction.start(); const newTicksToCreate: PnlTicksCreateObject[] = await - getPnlTicksCreateObjects(blockHeight, blockTime, txId); + getPnlTicksCreateObjects(txId); await Transaction.rollback(txId); expect(newTicksToCreate.length).toEqual(2); expect(newTicksToCreate).toEqual( diff --git a/indexer/services/roundtable/src/helpers/pnl-ticks-helper.ts b/indexer/services/roundtable/src/helpers/pnl-ticks-helper.ts index ee0f6d5970..c899082bfc 100644 --- a/indexer/services/roundtable/src/helpers/pnl-ticks-helper.ts +++ b/indexer/services/roundtable/src/helpers/pnl-ticks-helper.ts @@ -1,6 +1,8 @@ import { logger, stats } from '@dydxprotocol-indexer/base'; import { AssetPositionTable, + BlockFromDatabase, + BlockTable, FundingIndexMap, FundingIndexUpdatesTable, helpers, @@ -50,11 +52,15 @@ export function normalizeStartTime( * @param blockHeight: consider transfers up until this block height. */ export async function getPnlTicksCreateObjects( - blockHeight: string, - blockTime: IsoString, txId: number, ): Promise { const startGetPnlTicksCreateObjects: number = Date.now(); + const latestBlock: BlockFromDatabase = await BlockTable.getLatest({ + readReplica: true, + txId, + }); + const blockHeight: string = latestBlock.blockHeight; + const blockTime: string = latestBlock.time; const pnlTicksToBeCreatedAt: DateTime = DateTime.utc(); const [ mostRecentPnlTicks, diff --git a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts index 36d7f40698..fde4918a18 100644 --- a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts +++ b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts @@ -55,7 +55,7 @@ export default async function runTask(): Promise { let newTicksToCreate: PnlTicksCreateObject[] = []; try { await perpetualMarketRefresher.updatePerpetualMarkets(); - newTicksToCreate = await getPnlTicksCreateObjects(latestBlockHeight, latestBlockTime, txId); + newTicksToCreate = await getPnlTicksCreateObjects(txId); } catch (error) { logger.error({ at: 'create-pnl-ticks#runTask', From 07cdd6c69093abdc0ead73a00672a927482fe15e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:19:58 -0500 Subject: [PATCH 038/120] Dont set default value for fills rows (backport #2552) (#2553) Co-authored-by: Adam Fraser --- .../20240829161445_add_fills_affiliateearnedrevshare.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20240829161445_add_fills_affiliateearnedrevshare.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20240829161445_add_fills_affiliateearnedrevshare.ts index cc4f7b59b8..694eac939b 100644 --- a/indexer/packages/postgres/src/db/migrations/migration_files/20240829161445_add_fills_affiliateearnedrevshare.ts +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20240829161445_add_fills_affiliateearnedrevshare.ts @@ -2,7 +2,7 @@ import * as Knex from 'knex'; export async function up(knex: Knex): Promise { await knex.schema.table('fills', (table) => { - table.string('affiliateEarnedRevShare').notNullable().defaultTo('0'); + table.string('affiliateEarnedRevShare'); }); } From 4659c3037e1a9e1be4fcd43e9c41d6947d3e5716 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:34:41 -0400 Subject: [PATCH 039/120] Update MsgSetActiveState proto (#2337) --- proto/dydxprotocol/accountplus/tx.proto | 2 +- protocol/x/accountplus/types/tx.pb.go | 72 ++++++++++++------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/proto/dydxprotocol/accountplus/tx.proto b/proto/dydxprotocol/accountplus/tx.proto index 30ff59f33b..eef411ec22 100644 --- a/proto/dydxprotocol/accountplus/tx.proto +++ b/proto/dydxprotocol/accountplus/tx.proto @@ -50,7 +50,7 @@ message MsgRemoveAuthenticatorResponse { bool success = 1; } // MsgSetActiveState sets the active state of the module. message MsgSetActiveState { - option (amino.name) = "osmosis/smartaccount/set-active-state"; + option (amino.name) = "dydxprotocol/accountplus/set-active-state"; option (cosmos.msg.v1.signer) = "authority"; // Authority is the address that may send this message. diff --git a/protocol/x/accountplus/types/tx.pb.go b/protocol/x/accountplus/types/tx.pb.go index b813711a49..c54ddfee4d 100644 --- a/protocol/x/accountplus/types/tx.pb.go +++ b/protocol/x/accountplus/types/tx.pb.go @@ -388,42 +388,42 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/accountplus/tx.proto", fileDescriptor_2d1c240983fd17d6) } var fileDescriptor_2d1c240983fd17d6 = []byte{ - // 557 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x31, 0x6b, 0xdb, 0x40, - 0x14, 0x8e, 0x6c, 0x93, 0x26, 0xd7, 0x12, 0x6a, 0xa5, 0x38, 0x8a, 0x03, 0x22, 0x35, 0x14, 0x8c, - 0x8b, 0xac, 0xb6, 0x69, 0x9b, 0x60, 0xc8, 0xe0, 0x40, 0xbb, 0x79, 0x91, 0x03, 0x85, 0x2e, 0xe6, - 0x72, 0x77, 0xc8, 0x07, 0x96, 0x4e, 0xe8, 0x9d, 0x8d, 0x3c, 0x95, 0x76, 0xec, 0xd4, 0x3f, 0xd0, - 0x7f, 0xd0, 0x21, 0x43, 0x7f, 0x44, 0xc7, 0xd0, 0xa9, 0x63, 0xb1, 0x87, 0xfc, 0x84, 0xae, 0x45, - 0x27, 0xd9, 0xb1, 0x1c, 0x39, 0xc4, 0x8b, 0xad, 0x77, 0xef, 0x7b, 0xdf, 0xfb, 0xbe, 0xa7, 0x77, - 0x42, 0x4f, 0xe9, 0x98, 0x46, 0x41, 0x28, 0xa4, 0x20, 0x62, 0x60, 0x63, 0x42, 0xc4, 0xd0, 0x97, - 0xc1, 0x60, 0x08, 0xb6, 0x8c, 0x9a, 0xea, 0x5c, 0x37, 0x16, 0x21, 0xcd, 0x05, 0x48, 0x75, 0x9f, - 0x08, 0xf0, 0x04, 0xf4, 0x54, 0xd2, 0x4e, 0x82, 0xa4, 0xa8, 0xba, 0x97, 0x44, 0xb6, 0x07, 0xae, - 0x3d, 0x7a, 0x19, 0xff, 0xa5, 0x89, 0x32, 0xf6, 0xb8, 0x2f, 0x6c, 0xf5, 0x9b, 0x1c, 0xd5, 0x7e, - 0x68, 0x68, 0xb7, 0x03, 0x6e, 0x9b, 0xd2, 0xf6, 0x50, 0xf6, 0x99, 0x2f, 0x39, 0xc1, 0x52, 0x84, - 0x7a, 0x05, 0x6d, 0x02, 0xf3, 0x29, 0x0b, 0x0d, 0xed, 0x50, 0xab, 0x6f, 0x3b, 0x69, 0xa4, 0x5b, - 0x48, 0xc7, 0x8b, 0xc0, 0x9e, 0x1c, 0x07, 0xcc, 0x28, 0x28, 0x4c, 0x39, 0x93, 0x39, 0x1f, 0x07, - 0x4c, 0xd7, 0x51, 0x89, 0x62, 0x89, 0x8d, 0xe2, 0xa1, 0x56, 0x7f, 0xe4, 0xa8, 0xe7, 0x56, 0xeb, - 0xcb, 0xf5, 0x65, 0x23, 0xe5, 0xfb, 0x7a, 0x7d, 0xd9, 0x68, 0xac, 0x1c, 0x03, 0xa6, 0xd4, 0xca, - 0x70, 0xd6, 0x8e, 0xd1, 0x41, 0x8e, 0x5a, 0x87, 0x41, 0x20, 0x7c, 0x60, 0xba, 0x81, 0x1e, 0xc0, - 0x90, 0x10, 0x06, 0xa0, 0x64, 0x6f, 0x39, 0xb3, 0xb0, 0xf6, 0x09, 0x55, 0x3a, 0xe0, 0x3a, 0xcc, - 0x13, 0x23, 0x76, 0x3f, 0xa7, 0x3b, 0xa8, 0xc0, 0xa9, 0x72, 0x56, 0x72, 0x0a, 0x9c, 0xb6, 0x4e, - 0x97, 0x64, 0x5b, 0x2b, 0x65, 0x87, 0xaa, 0xcb, 0x92, 0xf2, 0x16, 0x32, 0xf3, 0x05, 0xdc, 0x43, - 0xfc, 0x77, 0x0d, 0x95, 0x3b, 0xe0, 0x76, 0x99, 0x6c, 0x13, 0xc9, 0x47, 0xac, 0x2b, 0xb1, 0x64, - 0xfa, 0x5b, 0xb4, 0x1d, 0xb7, 0x10, 0x21, 0x97, 0xe3, 0x44, 0xfb, 0x99, 0xf1, 0xfb, 0xa7, 0xf5, - 0x24, 0xdd, 0x85, 0x36, 0xa5, 0x21, 0x03, 0xe8, 0xca, 0x90, 0xfb, 0xae, 0x73, 0x03, 0x8d, 0x0d, - 0x63, 0x45, 0xa3, 0xcc, 0x6d, 0x39, 0x69, 0xd4, 0x3a, 0x89, 0x0d, 0xde, 0xe0, 0x62, 0x8f, 0xcf, - 0x14, 0x15, 0x07, 0x1b, 0x3c, 0x1c, 0xca, 0xd4, 0xa3, 0x0d, 0x4c, 0x5a, 0x49, 0x8d, 0x05, 0xb1, - 0x92, 0xda, 0x01, 0xda, 0xbf, 0x25, 0x6f, 0x66, 0xab, 0xf6, 0x1e, 0x3d, 0x3c, 0x8f, 0xde, 0x45, - 0x92, 0xf9, 0xc0, 0x85, 0xaf, 0x1f, 0xa3, 0x3d, 0x60, 0x03, 0x46, 0x24, 0xa3, 0xbd, 0xcc, 0x84, - 0x62, 0xd7, 0xc5, 0x7a, 0xc9, 0xa9, 0xcc, 0xd2, 0x99, 0x29, 0xc1, 0xab, 0x7f, 0x05, 0x54, 0xec, - 0x80, 0xab, 0x47, 0xe8, 0xf1, 0xad, 0x6d, 0xb5, 0x9a, 0xab, 0xee, 0x49, 0x33, 0x67, 0x5d, 0xaa, - 0x6f, 0xd6, 0x82, 0xcf, 0x5f, 0xd0, 0x67, 0x0d, 0xed, 0xe6, 0x6d, 0xd0, 0x8b, 0x3b, 0xe9, 0x72, - 0x2a, 0xaa, 0x27, 0xeb, 0x56, 0xcc, 0x35, 0x84, 0x68, 0x67, 0x69, 0x0d, 0x9e, 0xdf, 0xc9, 0x95, - 0x05, 0x57, 0x8f, 0xd6, 0x00, 0xcf, 0x7a, 0x9e, 0x7d, 0xf8, 0x35, 0x31, 0xb5, 0xab, 0x89, 0xa9, - 0xfd, 0x9d, 0x98, 0xda, 0xb7, 0xa9, 0xb9, 0x71, 0x35, 0x35, 0x37, 0xfe, 0x4c, 0xcd, 0x8d, 0x8f, - 0xa7, 0x2e, 0x97, 0xfd, 0xe1, 0x45, 0x93, 0x08, 0xcf, 0xce, 0x5c, 0x87, 0xd1, 0x6b, 0x8b, 0xf4, - 0x31, 0xf7, 0xed, 0xf9, 0x49, 0x94, 0xfd, 0xc0, 0x8d, 0x03, 0x06, 0x17, 0x9b, 0x2a, 0x7b, 0xf4, - 0x3f, 0x00, 0x00, 0xff, 0xff, 0x67, 0x49, 0xc8, 0xe0, 0x09, 0x05, 0x00, 0x00, + // 548 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xae, 0x93, 0xa8, 0xb4, 0x07, 0xaa, 0x88, 0x8b, 0x52, 0x37, 0x95, 0xac, 0x92, 0x29, 0x04, + 0x39, 0x06, 0x0a, 0x14, 0x45, 0x74, 0x48, 0x25, 0xd8, 0xb2, 0x38, 0x95, 0x90, 0x58, 0x22, 0xf7, + 0xee, 0xc9, 0x39, 0x29, 0xf1, 0x59, 0x7e, 0x97, 0xc8, 0x99, 0x10, 0x8c, 0x4c, 0xfc, 0x05, 0x76, + 0x86, 0x0e, 0xfc, 0x08, 0xc6, 0x8a, 0x89, 0x11, 0x25, 0x43, 0x7f, 0x02, 0x2b, 0xf2, 0x39, 0x49, + 0xe3, 0xd4, 0xa9, 0x9a, 0xc5, 0xf6, 0xbb, 0xf7, 0xbd, 0xf7, 0xbe, 0xef, 0xf9, 0xb3, 0xc9, 0x63, + 0x36, 0x62, 0x51, 0x10, 0x0a, 0x29, 0xa8, 0xe8, 0xd9, 0x2e, 0xa5, 0x62, 0xe0, 0xcb, 0xa0, 0x37, + 0x40, 0x5b, 0x46, 0x75, 0x75, 0xae, 0x1b, 0x8b, 0x90, 0xfa, 0x02, 0xa4, 0xbc, 0x4f, 0x05, 0xf6, + 0x05, 0x76, 0x54, 0xd2, 0x4e, 0x82, 0xa4, 0xa8, 0xbc, 0x97, 0x44, 0x76, 0x1f, 0x3d, 0x7b, 0xf8, + 0x3c, 0xbe, 0x4d, 0x13, 0x45, 0xb7, 0xcf, 0x7d, 0x61, 0xab, 0x6b, 0x72, 0x54, 0xf9, 0xa1, 0x91, + 0xdd, 0x16, 0x7a, 0x4d, 0xc6, 0x9a, 0x03, 0xd9, 0x05, 0x5f, 0x72, 0xea, 0x4a, 0x11, 0xea, 0x25, + 0xb2, 0x89, 0xe0, 0x33, 0x08, 0x0d, 0xed, 0x50, 0xab, 0x6e, 0x3b, 0xd3, 0x48, 0xb7, 0x88, 0xee, + 0x2e, 0x02, 0x3b, 0x72, 0x14, 0x80, 0x91, 0x53, 0x98, 0x62, 0x2a, 0x73, 0x36, 0x0a, 0x40, 0xd7, + 0x49, 0x81, 0xb9, 0xd2, 0x35, 0xf2, 0x87, 0x5a, 0xf5, 0x81, 0xa3, 0x9e, 0x1b, 0x8d, 0x2f, 0x57, + 0x17, 0xb5, 0x69, 0xbf, 0xaf, 0x57, 0x17, 0xb5, 0xda, 0xca, 0x35, 0xb8, 0x8c, 0x59, 0xa9, 0x9e, + 0x95, 0x63, 0x72, 0x90, 0xc1, 0xd6, 0x01, 0x0c, 0x84, 0x8f, 0xa0, 0x1b, 0xe4, 0x1e, 0x0e, 0x28, + 0x05, 0x44, 0x45, 0x7b, 0xcb, 0x99, 0x85, 0x95, 0x4f, 0xa4, 0xd4, 0x42, 0xcf, 0x81, 0xbe, 0x18, + 0xc2, 0xdd, 0x94, 0xee, 0x90, 0x1c, 0x67, 0x4a, 0x59, 0xc1, 0xc9, 0x71, 0xd6, 0x38, 0x59, 0xa2, + 0x6d, 0xad, 0xa4, 0x1d, 0xaa, 0x29, 0x4b, 0xcc, 0x1b, 0xc4, 0xcc, 0x26, 0x70, 0x07, 0xf2, 0xdf, + 0x35, 0x52, 0x6c, 0xa1, 0xd7, 0x06, 0xd9, 0xa4, 0x92, 0x0f, 0xa1, 0x2d, 0x5d, 0x09, 0xfa, 0x6b, + 0xb2, 0x1d, 0x8f, 0x10, 0x21, 0x97, 0xa3, 0x84, 0xfb, 0xa9, 0xf1, 0xfb, 0xa7, 0xf5, 0x68, 0xea, + 0x85, 0x26, 0x63, 0x21, 0x20, 0xb6, 0x65, 0xc8, 0x7d, 0xcf, 0xb9, 0x86, 0xc6, 0x82, 0x5d, 0xd5, + 0x46, 0x89, 0xdb, 0x72, 0xa6, 0x51, 0xe3, 0x6d, 0x2c, 0xf0, 0x1a, 0x17, 0x6b, 0x7c, 0xb2, 0x52, + 0x23, 0x82, 0xb4, 0x92, 0x3a, 0x0b, 0x63, 0x36, 0x95, 0x03, 0xb2, 0x7f, 0x83, 0xe2, 0x4c, 0x5a, + 0xe5, 0x3d, 0xb9, 0x7f, 0x16, 0xbd, 0x8b, 0x24, 0xf8, 0xc8, 0x85, 0xaf, 0x1f, 0x93, 0x3d, 0x84, + 0x1e, 0x50, 0x09, 0xac, 0x93, 0xda, 0x52, 0xac, 0x3c, 0x5f, 0x2d, 0x38, 0xa5, 0x59, 0x3a, 0xb5, + 0x29, 0x7c, 0xf1, 0x2f, 0x47, 0xf2, 0x2d, 0xf4, 0xf4, 0x88, 0x3c, 0xbc, 0xe1, 0x58, 0xab, 0xbe, + 0xea, 0x5b, 0xa9, 0x67, 0x58, 0xa6, 0xfc, 0x6a, 0x2d, 0xf8, 0xfc, 0x25, 0x7d, 0xd6, 0xc8, 0x6e, + 0x96, 0x8b, 0x9e, 0xdd, 0xda, 0x2e, 0xa3, 0xa2, 0xfc, 0x66, 0xdd, 0x8a, 0x39, 0x87, 0x90, 0xec, + 0x2c, 0x59, 0xe1, 0xe9, 0xad, 0xbd, 0xd2, 0xe0, 0xf2, 0xd1, 0x1a, 0xe0, 0xd9, 0xcc, 0xd3, 0x0f, + 0xbf, 0xc6, 0xa6, 0x76, 0x39, 0x36, 0xb5, 0xbf, 0x63, 0x53, 0xfb, 0x36, 0x31, 0x37, 0x2e, 0x27, + 0xe6, 0xc6, 0x9f, 0x89, 0xb9, 0xf1, 0xf1, 0xc4, 0xe3, 0xb2, 0x3b, 0x38, 0xaf, 0x53, 0xd1, 0xb7, + 0x53, 0x76, 0x19, 0xbe, 0xb4, 0x68, 0xd7, 0xe5, 0xbe, 0x3d, 0x3f, 0x89, 0xd2, 0x3f, 0xb9, 0x51, + 0x00, 0x78, 0xbe, 0xa9, 0xb2, 0x47, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x28, 0x17, 0xd4, 0xbe, + 0x0d, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 12a17430c0665bbac2b5a9fd2a4b2ffe022f1a92 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 25 Sep 2024 12:38:46 -0400 Subject: [PATCH 040/120] Mergify for v7 branches (#2343) --- .github/mergify.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/mergify.yml b/.github/mergify.yml index fe2a908f52..bb52ef89d1 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -117,4 +117,20 @@ pull_request_rules: backport: branches: - release/protocol/v6.x + - name: backport to release/indexer/v7.x branch + conditions: + - base=main + - label=backport/indexer/v7.x + actions: + backport: + branches: + - release/indexer/v7.x + - name: backport to release/protocol/v7.x branch + conditions: + - base=main + - label=backport/protocol/v7.x + actions: + backport: + branches: + - release/protocol/v7.x From 3580b165e6fc874aa650a4190d810ac6de48aca4 Mon Sep 17 00:00:00 2001 From: ttl33 <19664986+ttl33@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:46:36 -0400 Subject: [PATCH 041/120] Fix: deterministically fetch perp info from state (#2341) --- protocol/testutil/constants/positions.go | 7 ++ protocol/x/subaccounts/keeper/subaccount.go | 19 +-- .../x/subaccounts/keeper/subaccount_test.go | 112 ++++++++++++++++++ 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/protocol/testutil/constants/positions.go b/protocol/testutil/constants/positions.go index 4669fded40..3913e12bde 100644 --- a/protocol/testutil/constants/positions.go +++ b/protocol/testutil/constants/positions.go @@ -99,6 +99,13 @@ var ( big.NewInt(0), big.NewInt(0), ) + // SOL positions + PerpetualPosition_OneSolLong = *testutil.CreateSinglePerpetualPosition( + 2, + big.NewInt(100_000_000_000), // 1 SOL + big.NewInt(0), + big.NewInt(0), + ) // Long position for arbitrary isolated market PerpetualPosition_OneISOLong = *testutil.CreateSinglePerpetualPosition( 3, diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index 8ee77a9d13..5eb650cce0 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -770,30 +770,33 @@ func (k Keeper) GetAllRelevantPerpetuals( perptypes.PerpInfos, error, ) { - subaccountIds := make(map[types.SubaccountId]struct{}) - perpIds := make(map[uint32]struct{}) + subaccountIdsSet := make(map[types.SubaccountId]struct{}) + perpIdsSet := make(map[uint32]struct{}) // Add all relevant perpetuals in every update. for _, update := range updates { // If this subaccount has not been processed already, get all of its existing perpetuals. - if _, exists := subaccountIds[update.SubaccountId]; !exists { + if _, exists := subaccountIdsSet[update.SubaccountId]; !exists { sa := k.GetSubaccount(ctx, update.SubaccountId) for _, postition := range sa.PerpetualPositions { - perpIds[postition.PerpetualId] = struct{}{} + perpIdsSet[postition.PerpetualId] = struct{}{} } - subaccountIds[update.SubaccountId] = struct{}{} + subaccountIdsSet[update.SubaccountId] = struct{}{} } // Add all perpetuals in the update. for _, perpUpdate := range update.PerpetualUpdates { - perpIds[perpUpdate.GetId()] = struct{}{} + perpIdsSet[perpUpdate.GetId()] = struct{}{} } } + // Important: Sort the perpIds to ensure determinism! + sortedPerpIds := lib.GetSortedKeys[lib.Sortable[uint32]](perpIdsSet) + // Get all perpetual information from state. ltCache := make(map[uint32]perptypes.LiquidityTier) - perpInfos := make(perptypes.PerpInfos, len(perpIds)) - for perpId := range perpIds { + perpInfos := make(perptypes.PerpInfos, len(sortedPerpIds)) + for _, perpId := range sortedPerpIds { perpetual, price, err := k.perpetualsKeeper.GetPerpetualAndMarketPrice(ctx, perpId) if err != nil { return nil, err diff --git a/protocol/x/subaccounts/keeper/subaccount_test.go b/protocol/x/subaccounts/keeper/subaccount_test.go index e44a8b5edd..1eb7141fda 100644 --- a/protocol/x/subaccounts/keeper/subaccount_test.go +++ b/protocol/x/subaccounts/keeper/subaccount_test.go @@ -10,6 +10,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/dydxprotocol/v4-chain/protocol/lib" + storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/dtypes" @@ -6019,3 +6020,114 @@ func TestGetNetCollateralAndMarginRequirements(t *testing.T) { }) } } + +func TestGetAllRelevantPerpetuals_Deterministic(t *testing.T) { + tests := map[string]struct { + // state + perpetuals []perptypes.Perpetual + + // subaccount state + assetPositions []*types.AssetPosition + perpetualPositions []*types.PerpetualPosition + + // updates + assetUpdates []types.AssetUpdate + perpetualUpdates []types.PerpetualUpdate + }{ + "Gas used is deterministic when erroring on gas usage": { + assetPositions: testutil.CreateUsdcAssetPositions(big.NewInt(10_000_000_001)), // $10,000.000001 + perpetuals: []perptypes.Perpetual{ + constants.BtcUsd_NoMarginRequirement, + constants.EthUsd_NoMarginRequirement, + constants.SolUsd_20PercentInitial_10PercentMaintenance, + }, + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + &constants.PerpetualPosition_OneTenthEthLong, + &constants.PerpetualPosition_OneSolLong, + }, + assetUpdates: []types.AssetUpdate{ + { + AssetId: constants.Usdc.Id, + BigQuantumsDelta: big.NewInt(1_000_000), // +1 USDC + }, + }, + perpetualUpdates: []types.PerpetualUpdate{ + { + PerpetualId: uint32(0), + BigQuantumsDelta: big.NewInt(-200_000_000), // -2 BTC + }, + { + PerpetualId: uint32(1), + BigQuantumsDelta: big.NewInt(250_000_000), // .25 ETH + }, + { + PerpetualId: uint32(2), + BigQuantumsDelta: big.NewInt(500_000_000), // .005 SOL + }, + }, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + // Setup. + ctx, keeper, pricesKeeper, perpetualsKeeper, _, _, assetsKeeper, _, _, _, _ := keepertest.SubaccountsKeepers( + t, + true, + ) + keepertest.CreateTestMarkets(t, ctx, pricesKeeper) + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) + for _, p := range tc.perpetuals { + perpetualsKeeper.SetPerpetualForTest(ctx, p) + } + require.NoError(t, keepertest.CreateUsdcAsset(ctx, assetsKeeper)) + + subaccount := createNSubaccount(keeper, ctx, 1, big.NewInt(1_000))[0] + subaccount.PerpetualPositions = tc.perpetualPositions + subaccount.AssetPositions = tc.assetPositions + keeper.SetSubaccount(ctx, subaccount) + subaccountId := *subaccount.Id + + update := types.Update{ + SubaccountId: subaccountId, + AssetUpdates: tc.assetUpdates, + PerpetualUpdates: tc.perpetualUpdates, + } + + // Execute. + gasUsedBefore := ctx.GasMeter().GasConsumed() + _, err := keeper.GetAllRelevantPerpetuals(ctx, []types.Update{update}) + require.NoError(t, err) + gasUsedAfter := ctx.GasMeter().GasConsumed() + + gasUsed := uint64(0) + // Run 100 times since it's highly unlikely gas usage is deterministic over 100 times if + // there's non-determinism. + for range 100 { + // divide by 2 so that the state read fails at least second to last time. + ctxWithLimitedGas := ctx.WithGasMeter(storetypes.NewGasMeter((gasUsedAfter - gasUsedBefore) / 2)) + + require.PanicsWithValue( + t, + storetypes.ErrorOutOfGas{Descriptor: "ReadFlat"}, + func() { + _, _ = keeper.GetAllRelevantPerpetuals(ctxWithLimitedGas, []types.Update{update}) + }, + ) + + if gasUsed == 0 { + gasUsed = ctxWithLimitedGas.GasMeter().GasConsumed() + require.Greater(t, gasUsed, uint64(0)) + } else { + require.Equal( + t, + gasUsed, + ctxWithLimitedGas.GasMeter().GasConsumed(), + "Gas usage when out of gas is not deterministic", + ) + } + } + }) + } +} From bb77d1985307c14c0efd112ba4caad20fffc7889 Mon Sep 17 00:00:00 2001 From: shrenujb <98204323+shrenujb@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:58:00 -0400 Subject: [PATCH 042/120] [TRA-617] Integrate PML and Megavault (#2331) Signed-off-by: Shrenuj Bansal --- .../codegen/dydxprotocol/listing/genesis.ts | 19 ++- proto/dydxprotocol/listing/genesis.proto | 7 + protocol/app/app.go | 2 + .../app/testdata/default_genesis_state.json | 7 +- .../scripts/genesis/sample_pregenesis.json | 7 +- protocol/testing/genesis.sh | 8 + protocol/testutil/constants/genesis.go | 7 +- protocol/testutil/keeper/listing.go | 4 + protocol/x/clob/keeper/clob_pair.go | 30 ++-- protocol/x/listing/genesis.go | 4 + protocol/x/listing/keeper/keeper.go | 3 + protocol/x/listing/keeper/listing.go | 73 ++++++++- protocol/x/listing/keeper/listing_test.go | 152 ++++++++++++++++-- .../msg_create_market_permissionless.go | 8 +- .../msg_create_market_permissionless_test.go | 58 ++++++- protocol/x/listing/module.go | 3 + protocol/x/listing/types/expected_keepers.go | 31 +++- protocol/x/listing/types/genesis.go | 3 +- protocol/x/listing/types/genesis.pb.go | 80 +++++++-- protocol/x/listing/types/params.go | 2 +- protocol/x/vault/keeper/params.go | 14 ++ 21 files changed, 462 insertions(+), 60 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/genesis.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/genesis.ts index 6eb10a8756..ec58a89c8c 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/genesis.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/genesis.ts @@ -1,3 +1,4 @@ +import { ListingVaultDepositParams, ListingVaultDepositParamsSDKType } from "./params"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; /** GenesisState defines `x/listing`'s genesis state. */ @@ -8,6 +9,9 @@ export interface GenesisState { * listed */ hardCapForMarkets: number; + /** listing_vault_deposit_params is the params for PML megavault deposits */ + + listingVaultDepositParams?: ListingVaultDepositParams; } /** GenesisState defines `x/listing`'s genesis state. */ @@ -17,11 +21,15 @@ export interface GenesisStateSDKType { * listed */ hard_cap_for_markets: number; + /** listing_vault_deposit_params is the params for PML megavault deposits */ + + listing_vault_deposit_params?: ListingVaultDepositParamsSDKType; } function createBaseGenesisState(): GenesisState { return { - hardCapForMarkets: 0 + hardCapForMarkets: 0, + listingVaultDepositParams: undefined }; } @@ -31,6 +39,10 @@ export const GenesisState = { writer.uint32(8).uint32(message.hardCapForMarkets); } + if (message.listingVaultDepositParams !== undefined) { + ListingVaultDepositParams.encode(message.listingVaultDepositParams, writer.uint32(18).fork()).ldelim(); + } + return writer; }, @@ -47,6 +59,10 @@ export const GenesisState = { message.hardCapForMarkets = reader.uint32(); break; + case 2: + message.listingVaultDepositParams = ListingVaultDepositParams.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -59,6 +75,7 @@ export const GenesisState = { fromPartial(object: DeepPartial): GenesisState { const message = createBaseGenesisState(); message.hardCapForMarkets = object.hardCapForMarkets ?? 0; + message.listingVaultDepositParams = object.listingVaultDepositParams !== undefined && object.listingVaultDepositParams !== null ? ListingVaultDepositParams.fromPartial(object.listingVaultDepositParams) : undefined; return message; } diff --git a/proto/dydxprotocol/listing/genesis.proto b/proto/dydxprotocol/listing/genesis.proto index 98d3d29a07..2aefaaac79 100644 --- a/proto/dydxprotocol/listing/genesis.proto +++ b/proto/dydxprotocol/listing/genesis.proto @@ -1,6 +1,9 @@ syntax = "proto3"; package dydxprotocol.listing; +import "gogoproto/gogo.proto"; +import "dydxprotocol/listing/params.proto"; + option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/listing/types"; // GenesisState defines `x/listing`'s genesis state. @@ -8,4 +11,8 @@ message GenesisState { // hard_cap_for_markets is the hard cap for the number of markets that can be // listed uint32 hard_cap_for_markets = 1; + + // listing_vault_deposit_params is the params for PML megavault deposits + ListingVaultDepositParams listing_vault_deposit_params = 2 + [ (gogoproto.nullable) = false ]; } diff --git a/protocol/app/app.go b/protocol/app/app.go index d45a739b8e..0528e2b17c 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1206,6 +1206,7 @@ func New( app.ClobKeeper, &app.MarketMapKeeper, app.PerpetualsKeeper, + app.VaultKeeper, ) listingModule := listingmodule.NewAppModule( appCodec, @@ -1214,6 +1215,7 @@ func New( app.ClobKeeper, &app.MarketMapKeeper, app.PerpetualsKeeper, + app.VaultKeeper, ) // Initialize authenticators diff --git a/protocol/app/testdata/default_genesis_state.json b/protocol/app/testdata/default_genesis_state.json index e8fd038a30..48de48a5ba 100644 --- a/protocol/app/testdata/default_genesis_state.json +++ b/protocol/app/testdata/default_genesis_state.json @@ -353,7 +353,12 @@ } }, "listing": { - "hard_cap_for_markets": 0 + "hard_cap_for_markets": 500, + "listing_vault_deposit_params": { + "new_vault_deposit_amount": "10000000000", + "main_vault_deposit_amount": "0", + "num_blocks_to_lock_shares": 2592000 + } }, "params": null, "perpetuals": { diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index b3d0afbb32..6594f9c167 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -869,7 +869,12 @@ } }, "listing": { - "hard_cap_for_markets": 0 + "hard_cap_for_markets": 500, + "listing_vault_deposit_params": { + "main_vault_deposit_amount": "0", + "new_vault_deposit_amount": "10000000000", + "num_blocks_to_lock_shares": 2592000 + } }, "marketmap": { "last_updated": "0", diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index 28d1f8c6c7..69dab93c04 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -2258,6 +2258,14 @@ function edit_genesis() { # ICA Controller Params update_ica_controller_params + # Listing + # Set hard cap for markets + dasel put -t int -f "$GENESIS" ".app_state.listing.hard_cap_for_markets" -v '500' + # Set default listing vault deposit params + dasel put -t string -f "$GENESIS" ".app_state.listing.listing_vault_deposit_params.new_vault_deposit_amount" -v "10000000000" # 10_000 USDC + dasel put -t string -f "$GENESIS" ".app_state.listing.listing_vault_deposit_params.main_vault_deposit_amount" -v "0" # 0 USDC + dasel put -t int -f "$GENESIS" ".app_state.listing.listing_vault_deposit_params.num_blocks_to_lock_shares" -v '2592000' # 30 days + # Vaults # Set default quoting params. dasel put -t int -f "$GENESIS" ".app_state.vault.default_quoting_params.spread_min_ppm" -v '3000' diff --git a/protocol/testutil/constants/genesis.go b/protocol/testutil/constants/genesis.go index a33db9f187..f56364819b 100644 --- a/protocol/testutil/constants/genesis.go +++ b/protocol/testutil/constants/genesis.go @@ -873,7 +873,12 @@ const GenesisState = `{ } }, "listing": { - "hard_cap_for_markets": 0 + "hard_cap_for_markets": 500, + "listing_vault_deposit_params": { + "new_vault_deposit_amount": "10000000000", + "main_vault_deposit_amount": "0", + "num_blocks_to_lock_shares": 2592000 + } }, "perpetuals": { "liquidity_tiers": [ diff --git a/protocol/testutil/keeper/listing.go b/protocol/testutil/keeper/listing.go index 39e5b80cac..824eb50ef5 100644 --- a/protocol/testutil/keeper/listing.go +++ b/protocol/testutil/keeper/listing.go @@ -14,6 +14,7 @@ import ( 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" + vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" "github.com/stretchr/testify/mock" @@ -165,6 +166,7 @@ func ListingKeepers( perpetualsKeeper, clobKeeper, marketMapKeeper, + vaultKeeper, ) return []GenesisInitializer{keeper} @@ -182,6 +184,7 @@ func createListingKeeper( perpetualsKeeper *perpetualskeeper.Keeper, clobKeeper *clobkeeper.Keeper, marketMapKeeper *marketmapkeeper.Keeper, + vaultkeeper *vaultkeeper.Keeper, ) ( *keeper.Keeper, storetypes.StoreKey, @@ -201,6 +204,7 @@ func createListingKeeper( clobKeeper, marketMapKeeper, perpetualsKeeper, + vaultkeeper, ) return k, storeKey, mockTimeProvider diff --git a/protocol/x/clob/keeper/clob_pair.go b/protocol/x/clob/keeper/clob_pair.go index c03ebdfb6f..3b49d7c246 100644 --- a/protocol/x/clob/keeper/clob_pair.go +++ b/protocol/x/clob/keeper/clob_pair.go @@ -66,7 +66,10 @@ func (k Keeper) CreatePerpetualClobPair( return clobPair, err } - err := k.CreateClobPair(ctx, clobPair) + // Write the `ClobPair` to state. + k.SetClobPair(ctx, clobPair) + + err := k.CreateClobPairStructures(ctx, clobPair) if err != nil { return clobPair, err } @@ -162,22 +165,11 @@ func (k Keeper) createOrderbook(ctx sdk.Context, clobPair types.ClobPair) { k.MemClob.CreateOrderbook(clobPair) } -// CreateClobPair creates a new `ClobPair` in the store and creates the corresponding orderbook in the memclob. +// CreateClobPair performs all non stateful operations to create a CLOB pair. +// These include creating the corresponding orderbook in the memclob, the mapping between +// the CLOB pair and the perpetual and the indexer event. // This function returns an error if a value for the ClobPair's id already exists in state. -func (k Keeper) CreateClobPair(ctx sdk.Context, clobPair types.ClobPair) error { - // Validate the given clob pair id is not already in use. - if _, exists := k.GetClobPair(ctx, clobPair.GetClobPairId()); exists { - panic( - fmt.Sprintf( - "ClobPair with id %+v already exists in state", - clobPair.GetClobPairId(), - ), - ) - } - - // Write the `ClobPair` to state. - k.setClobPair(ctx, clobPair) - +func (k Keeper) CreateClobPairStructures(ctx sdk.Context, clobPair types.ClobPair) error { // Create the corresponding orderbook in the memclob. k.createOrderbook(ctx, clobPair) @@ -217,8 +209,8 @@ func (k Keeper) CreateClobPair(ctx sdk.Context, clobPair types.ClobPair) error { return nil } -// setClobPair sets a specific `ClobPair` in the store from its index. -func (k Keeper) setClobPair(ctx sdk.Context, clobPair types.ClobPair) { +// SetClobPair sets a specific `ClobPair` in the store from its index. +func (k Keeper) SetClobPair(ctx sdk.Context, clobPair types.ClobPair) { store := k.getClobPairStore(ctx) b := k.cdc.MustMarshal(&clobPair) store.Set(clobPairKey(clobPair.GetClobPairId()), b) @@ -567,7 +559,7 @@ func (k Keeper) UpdateClobPair( return err } - k.setClobPair(ctx, clobPair) + k.SetClobPair(ctx, clobPair) // Send UpdateClobPair to indexer. k.GetIndexerEventManager().AddTxnEvent( diff --git a/protocol/x/listing/genesis.go b/protocol/x/listing/genesis.go index fcd391c6ab..38c9d2c686 100644 --- a/protocol/x/listing/genesis.go +++ b/protocol/x/listing/genesis.go @@ -13,6 +13,10 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) if err := k.SetMarketsHardCap(ctx, genState.HardCapForMarkets); err != nil { panic(err) } + + if err := k.SetListingVaultDepositParams(ctx, genState.ListingVaultDepositParams); err != nil { + panic(err) + } } // ExportGenesis returns the module's exported genesis. diff --git a/protocol/x/listing/keeper/keeper.go b/protocol/x/listing/keeper/keeper.go index daf4c0c3a4..881fa63fe5 100644 --- a/protocol/x/listing/keeper/keeper.go +++ b/protocol/x/listing/keeper/keeper.go @@ -20,6 +20,7 @@ type ( ClobKeeper types.ClobKeeper MarketMapKeeper types.MarketMapKeeper PerpetualsKeeper types.PerpetualsKeeper + VaultKeeper types.VaultKeeper } ) @@ -31,6 +32,7 @@ func NewKeeper( clobKeeper types.ClobKeeper, marketMapKeeper types.MarketMapKeeper, perpetualsKeeper types.PerpetualsKeeper, + vaultKeeper types.VaultKeeper, ) *Keeper { return &Keeper{ cdc: cdc, @@ -40,6 +42,7 @@ func NewKeeper( ClobKeeper: clobKeeper, MarketMapKeeper: marketMapKeeper, PerpetualsKeeper: perpetualsKeeper, + VaultKeeper: vaultKeeper, } } diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 53ca3e8ca0..3141933630 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -2,6 +2,11 @@ package keeper import ( "math" + "math/big" + + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" + + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/dydxprotocol/v4-chain/protocol/lib" @@ -101,10 +106,12 @@ func (k Keeper) CreateClobPair( return 0, err } + k.ClobKeeper.SetClobPair(ctx, clobPair) + // Only create the clob pair if we are in deliver tx mode. This is to prevent populating // in memory data structures in the CLOB during simulation mode. if lib.IsDeliverTxMode(ctx) { - err := k.ClobKeeper.CreateClobPair(ctx, clobPair) + err := k.ClobKeeper.CreateClobPairStructures(ctx, clobPair) if err != nil { return 0, err } @@ -187,3 +194,67 @@ func (k Keeper) GetListingVaultDepositParams( k.cdc.MustUnmarshal(b, &vaultDepositParams) return vaultDepositParams } + +// Function to deposit to the megavault for a new PML market +// This function deposits money to the megavault, transfers the new vault +// deposit amount to the new market vault and locks the shares for the deposit +func (k Keeper) DepositToMegavaultforPML( + ctx sdk.Context, + fromSubaccount satypes.SubaccountId, + clobPairId uint32, +) error { + // Get the listing vault deposit params + vaultDepositParams := k.GetListingVaultDepositParams(ctx) + + // Deposit to the megavault + totalDepositAmount := new(big.Int).Add( + vaultDepositParams.NewVaultDepositAmount.BigInt(), + vaultDepositParams.MainVaultDepositAmount.BigInt(), + ) + mintedShares, err := k.VaultKeeper.DepositToMegavault( + ctx, + fromSubaccount, + totalDepositAmount, + ) + if err != nil { + return err + } + + vaultId := vaulttypes.VaultId{ + Type: vaulttypes.VaultType_VAULT_TYPE_CLOB, + Number: clobPairId, + } + + // Transfer the new vault deposit amount to the new market vault + err = k.VaultKeeper.AllocateToVault( + ctx, + vaultId, + vaultDepositParams.NewVaultDepositAmount.BigInt(), + ) + if err != nil { + return err + } + + // Lock the shares for the new vault deposit amount + err = k.VaultKeeper.LockShares( + ctx, + fromSubaccount.Owner, + vaulttypes.BigIntToNumShares(mintedShares), + uint32(ctx.BlockHeight())+vaultDepositParams.NumBlocksToLockShares, + ) + if err != nil { + return err + } + + // Activate vault to quoting status + err = k.VaultKeeper.SetVaultStatus( + ctx, + vaultId, + vaulttypes.VaultStatus_VAULT_STATUS_QUOTING, + ) + if err != nil { + return err + } + + return nil +} diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index 3e37a9ec09..4678a1bc7e 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -2,8 +2,20 @@ package keeper_test import ( "errors" + "math/big" "testing" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/util" + + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" + + asstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/stretchr/testify/mock" "github.com/dydxprotocol/v4-chain/protocol/lib" @@ -16,6 +28,7 @@ import ( pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" + comettypes "github.com/cometbft/cometbft/types" "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" "github.com/dydxprotocol/v4-chain/protocol/mocks" @@ -265,27 +278,138 @@ func TestCreateClobPair(t *testing.T) { clobPairId, err := keeper.CreateClobPair(ctx, perpetualId) require.NoError(t, err) + clobPair, found := clobKeeper.GetClobPair(ctx, clobtypes.ClobPairId(clobPairId)) + require.True(t, found) + require.Equal(t, clobtypes.ClobPair_STATUS_ACTIVE, clobPair.Status) + require.Equal( + t, + clobtypes.SubticksPerTick(types.SubticksPerTick_LongTail), + clobPair.GetClobPairSubticksPerTick(), + ) + require.Equal( + t, + types.DefaultStepBaseQuantums, + clobPair.GetClobPairMinOrderBaseQuantums().ToUint64(), + ) + require.Equal(t, perpetualId, clobPair.MustGetPerpetualId()) + // Check if the clob pair was created only if we are in deliverTx mode + _, found = clobKeeper.PerpetualIdToClobPairId[perpetualId] if tc.isDeliverTx { - clobPair, found := clobKeeper.GetClobPair(ctx, clobtypes.ClobPairId(clobPairId)) require.True(t, found) - require.Equal(t, clobtypes.ClobPair_STATUS_ACTIVE, clobPair.Status) - require.Equal( - t, - clobtypes.SubticksPerTick(types.SubticksPerTick_LongTail), - clobPair.GetClobPairSubticksPerTick(), - ) - require.Equal( - t, - types.DefaultStepBaseQuantums, - clobPair.GetClobPairMinOrderBaseQuantums().ToUint64(), - ) - require.Equal(t, perpetualId, clobPair.MustGetPerpetualId()) } else { - _, found := clobKeeper.GetClobPair(ctx, clobtypes.ClobPairId(clobPairId)) require.False(t, found) } }, ) } } + +func TestDepositToMegavaultforPML(t *testing.T) { + tests := map[string]struct { + address string + balance *big.Int + asset asstypes.Asset + clobPairId uint32 + + expectedErr string + }{ + "success": { + address: constants.AliceAccAddress.String(), + balance: big.NewInt(10_000_000_000), // 10k USDC + asset: *constants.Usdc, + clobPairId: 1, + + expectedErr: "", + }, + "failure - insufficient balance": { + address: constants.AliceAccAddress.String(), + balance: big.NewInt(0), + asset: *constants.Usdc, + clobPairId: 1, + + expectedErr: "NewlyUndercollateralized", + }, + "failure - invalid clob pair id": { + address: constants.AliceAccAddress.String(), + balance: big.NewInt(10_000_000_000), // 10k USDC + asset: *constants.Usdc, + clobPairId: 100, // non existent clob pair id + + expectedErr: "ClobPair not found", + }, + } + + for name, tc := range tests { + t.Run( + name, func(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn( + func() (genesis comettypes.GenesisDoc) { + genesis = testapp.DefaultGenesis() + // Initialize vault with its existing equity. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *satypes.GenesisState) { + genesisState.Subaccounts = []satypes.Subaccount{ + { + Id: &vaulttypes.MegavaultMainSubaccount, + AssetPositions: []*satypes.AssetPosition{ + testutil.CreateSingleAssetPosition( + 0, + big.NewInt(1_000_000), + ), + }, + }, + { + Id: &satypes.SubaccountId{ + Owner: tc.address, + Number: 0, + }, + AssetPositions: []*satypes.AssetPosition{ + testutil.CreateSingleAssetPosition( + tc.asset.Id, + tc.balance, + ), + }, + }, + } + }, + ) + return genesis + }, + ).Build() + ctx := tApp.InitChain() + + // Set existing total shares. + err := tApp.App.VaultKeeper.SetTotalShares( + ctx, + vaulttypes.BigIntToNumShares(big.NewInt(1_000_000)), + ) + require.NoError(t, err) + + err = tApp.App.ListingKeeper.DepositToMegavaultforPML( + ctx, + satypes.SubaccountId{ + Owner: tc.address, + Number: 0, + }, + tc.clobPairId, + ) + if tc.expectedErr != "" { + require.ErrorContains(t, err, tc.expectedErr) + } else { + require.NoError(t, err) + vaultParams, exists := tApp.App.VaultKeeper.GetVaultParams( + ctx, + vaulttypes.VaultId{ + Type: vaulttypes.VaultType_VAULT_TYPE_CLOB, + Number: tc.clobPairId, + }, + ) + require.True(t, exists) + require.Equal(t, vaulttypes.VaultStatus_VAULT_STATUS_QUOTING, vaultParams.Status) + } + }, + ) + } +} diff --git a/protocol/x/listing/keeper/msg_create_market_permissionless.go b/protocol/x/listing/keeper/msg_create_market_permissionless.go index 194ff01b08..a54cff5145 100644 --- a/protocol/x/listing/keeper/msg_create_market_permissionless.go +++ b/protocol/x/listing/keeper/msg_create_market_permissionless.go @@ -31,13 +31,17 @@ func (k msgServer) CreateMarketPermissionless( return nil, err } - _, err = k.Keeper.CreateClobPair(ctx, perpetualId) + clobPairId, err := k.Keeper.CreateClobPair(ctx, perpetualId) if err != nil { k.Logger(ctx).Error("failed to create clob pair for PML market", "error", err) return nil, err } - // TODO: vault deposit for PML + err = k.Keeper.DepositToMegavaultforPML(ctx, *msg.SubaccountId, clobPairId) + if err != nil { + k.Logger(ctx).Error("failed to deposit to megavault for PML market", "error", err) + return nil, err + } return &types.MsgCreateMarketPermissionlessResponse{}, nil } diff --git a/protocol/x/listing/keeper/msg_create_market_permissionless_test.go b/protocol/x/listing/keeper/msg_create_market_permissionless_test.go index a4c531739a..a1f351e0b2 100644 --- a/protocol/x/listing/keeper/msg_create_market_permissionless_test.go +++ b/protocol/x/listing/keeper/msg_create_market_permissionless_test.go @@ -1,12 +1,17 @@ package keeper_test import ( + "math/big" + + comettypes "github.com/cometbft/cometbft/types" testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/util" "github.com/dydxprotocol/v4-chain/protocol/x/listing/keeper" "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" oracletypes "github.com/skip-mev/slinky/pkg/types" marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" "github.com/skip-mev/slinky/x/marketmap/types/tickermetadata" @@ -19,27 +24,35 @@ func TestMsgCreateMarketPermissionless(t *testing.T) { tests := map[string]struct { ticker string hardCap uint32 + balance *big.Int expectedErr error }{ "success": { ticker: "TEST2-USD", hardCap: 300, + balance: big.NewInt(10_000_000_000), expectedErr: nil, }, "failure - hard cap reached": { - ticker: "TEST2-USD", - hardCap: 0, + ticker: "TEST2-USD", + hardCap: 0, + balance: big.NewInt(10_000_000_000), + expectedErr: types.ErrMarketsHardCapReached, }, "failure - ticker not found": { - ticker: "INVALID-USD", - hardCap: 300, + ticker: "INVALID-USD", + hardCap: 300, + balance: big.NewInt(10_000_000_000), + expectedErr: types.ErrMarketNotFound, }, "failure - market already listed": { - ticker: "BTC-USD", - hardCap: 300, + ticker: "BTC-USD", + hardCap: 300, + balance: big.NewInt(10_000_000_000), + expectedErr: pricestypes.ErrMarketParamPairAlreadyExists, }, } @@ -47,7 +60,38 @@ func TestMsgCreateMarketPermissionless(t *testing.T) { for name, tc := range tests { t.Run( name, func(t *testing.T) { - tApp := testapp.NewTestAppBuilder(t).Build() + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn( + func() (genesis comettypes.GenesisDoc) { + genesis = testapp.DefaultGenesis() + // Initialize vault with its existing equity. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *satypes.GenesisState) { + genesisState.Subaccounts = []satypes.Subaccount{ + { + Id: &vaulttypes.MegavaultMainSubaccount, + AssetPositions: []*satypes.AssetPosition{ + testutil.CreateSingleAssetPosition( + 0, + big.NewInt(1_000_000), + ), + }, + }, + { + Id: &constants.Alice_Num0, + AssetPositions: []*satypes.AssetPosition{ + testutil.CreateSingleAssetPosition( + 0, + tc.balance, + ), + }, + }, + } + }, + ) + return genesis + }, + ).Build() ctx := tApp.InitChain() k := tApp.App.ListingKeeper ms := keeper.NewMsgServerImpl(k) diff --git a/protocol/x/listing/module.go b/protocol/x/listing/module.go index 07f2fdef9a..819e921c13 100644 --- a/protocol/x/listing/module.go +++ b/protocol/x/listing/module.go @@ -103,6 +103,7 @@ type AppModule struct { clobKeeper types.ClobKeeper marketMapKeeper types.MarketMapKeeper perpetualsKeeper types.PerpetualsKeeper + vaultKeeper types.VaultKeeper } func NewAppModule( @@ -112,6 +113,7 @@ func NewAppModule( clobKeeper types.ClobKeeper, marketMapKeeper types.MarketMapKeeper, perpetualsKeeper types.PerpetualsKeeper, + vaultKeeper types.VaultKeeper, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), @@ -120,6 +122,7 @@ func NewAppModule( clobKeeper: clobKeeper, marketMapKeeper: marketMapKeeper, perpetualsKeeper: perpetualsKeeper, + vaultKeeper: vaultKeeper, } } diff --git a/protocol/x/listing/types/expected_keepers.go b/protocol/x/listing/types/expected_keepers.go index 5201a05b5d..d6b72ac3f9 100644 --- a/protocol/x/listing/types/expected_keepers.go +++ b/protocol/x/listing/types/expected_keepers.go @@ -1,6 +1,10 @@ package types import ( + "math/big" + + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" + sdk "github.com/cosmos/cosmos-sdk/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" @@ -30,7 +34,8 @@ type ClobKeeper interface { ) (clobtypes.ClobPair, error) AcquireNextClobPairID(ctx sdk.Context) uint32 ValidateClobPairCreation(ctx sdk.Context, clobPair *clobtypes.ClobPair) error - CreateClobPair(ctx sdk.Context, clobPair clobtypes.ClobPair) error + CreateClobPairStructures(ctx sdk.Context, clobPair clobtypes.ClobPair) error + SetClobPair(ctx sdk.Context, clobPair clobtypes.ClobPair) } type MarketMapKeeper interface { @@ -59,3 +64,27 @@ type PerpetualsKeeper interface { AcquireNextPerpetualID(ctx sdk.Context) uint32 GetAllPerpetuals(ctx sdk.Context) (list []perpetualtypes.Perpetual) } + +type VaultKeeper interface { + DepositToMegavault( + ctx sdk.Context, + fromSubaccount satypes.SubaccountId, + quoteQuantums *big.Int, + ) (mintedShares *big.Int, err error) + AllocateToVault( + ctx sdk.Context, + vaultId vaulttypes.VaultId, + quantums *big.Int, + ) error + LockShares( + ctx sdk.Context, + ownerAddress string, + sharesToLock vaulttypes.NumShares, + tilBlock uint32, + ) error + SetVaultStatus( + ctx sdk.Context, + vaultId vaulttypes.VaultId, + status vaulttypes.VaultStatus, + ) error +} diff --git a/protocol/x/listing/types/genesis.go b/protocol/x/listing/types/genesis.go index 0bbef0cd95..ae7b369acf 100644 --- a/protocol/x/listing/types/genesis.go +++ b/protocol/x/listing/types/genesis.go @@ -3,7 +3,8 @@ package types // DefaultGenesis returns the default stats genesis state. func DefaultGenesis() *GenesisState { return &GenesisState{ - HardCapForMarkets: 0, + HardCapForMarkets: 500, + ListingVaultDepositParams: DefaultParams(), } } diff --git a/protocol/x/listing/types/genesis.pb.go b/protocol/x/listing/types/genesis.pb.go index f42e4ac001..f8aaeda512 100644 --- a/protocol/x/listing/types/genesis.pb.go +++ b/protocol/x/listing/types/genesis.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -27,6 +28,8 @@ type GenesisState struct { // hard_cap_for_markets is the hard cap for the number of markets that can be // listed HardCapForMarkets uint32 `protobuf:"varint,1,opt,name=hard_cap_for_markets,json=hardCapForMarkets,proto3" json:"hard_cap_for_markets,omitempty"` + // listing_vault_deposit_params is the params for PML megavault deposits + ListingVaultDepositParams ListingVaultDepositParams `protobuf:"bytes,2,opt,name=listing_vault_deposit_params,json=listingVaultDepositParams,proto3" json:"listing_vault_deposit_params"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -69,6 +72,13 @@ func (m *GenesisState) GetHardCapForMarkets() uint32 { return 0 } +func (m *GenesisState) GetListingVaultDepositParams() ListingVaultDepositParams { + if m != nil { + return m.ListingVaultDepositParams + } + return ListingVaultDepositParams{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "dydxprotocol.listing.GenesisState") } @@ -78,19 +88,24 @@ func init() { } var fileDescriptor_d378c53d0f5a34b3 = []byte{ - // 186 bytes of a gzipped FileDescriptorProto + // 269 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4a, 0xa9, 0x4c, 0xa9, 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0xcf, 0xc9, 0x2c, 0x2e, 0xc9, 0xcc, 0x4b, 0xd7, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x03, 0x4b, 0x08, 0x89, 0x20, 0xab, 0xd1, - 0x83, 0xaa, 0x51, 0xb2, 0xe7, 0xe2, 0x71, 0x87, 0x28, 0x0b, 0x2e, 0x49, 0x2c, 0x49, 0x15, 0xd2, - 0xe7, 0x12, 0xc9, 0x48, 0x2c, 0x4a, 0x89, 0x4f, 0x4e, 0x2c, 0x88, 0x4f, 0xcb, 0x2f, 0x8a, 0xcf, - 0x4d, 0x2c, 0xca, 0x4e, 0x2d, 0x29, 0x96, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0x12, 0x04, 0xc9, - 0x39, 0x27, 0x16, 0xb8, 0xe5, 0x17, 0xf9, 0x42, 0x24, 0x9c, 0x82, 0x4f, 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, 0x32, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, - 0x57, 0x1f, 0xc5, 0x7d, 0x65, 0x26, 0xba, 0xc9, 0x19, 0x89, 0x99, 0x79, 0xfa, 0x70, 0x91, 0x0a, - 0xb8, 0x9b, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x32, 0xc6, 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x2c, 0x8a, 0x33, 0x2d, 0xd8, 0x00, 0x00, 0x00, + 0x83, 0xaa, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x8b, 0xea, 0x83, 0x58, 0x10, 0xb5, 0x52, + 0x8a, 0x58, 0xcd, 0x2b, 0x48, 0x2c, 0x4a, 0xcc, 0x85, 0x1a, 0xa7, 0xb4, 0x9d, 0x91, 0x8b, 0xc7, + 0x1d, 0x62, 0x41, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x3e, 0x97, 0x48, 0x46, 0x62, 0x51, 0x4a, + 0x7c, 0x72, 0x62, 0x41, 0x7c, 0x5a, 0x7e, 0x51, 0x7c, 0x6e, 0x62, 0x51, 0x76, 0x6a, 0x49, 0xb1, + 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x6f, 0x90, 0x20, 0x48, 0xce, 0x39, 0xb1, 0xc0, 0x2d, 0xbf, 0xc8, + 0x17, 0x22, 0x21, 0x54, 0xc6, 0x25, 0x03, 0x35, 0x39, 0xbe, 0x2c, 0xb1, 0x34, 0xa7, 0x24, 0x3e, + 0x25, 0xb5, 0x20, 0xbf, 0x38, 0xb3, 0x24, 0x1e, 0x62, 0x8f, 0x04, 0x93, 0x02, 0xa3, 0x06, 0xb7, + 0x91, 0xbe, 0x1e, 0x36, 0x77, 0xeb, 0xf9, 0x40, 0xe8, 0x30, 0x90, 0x46, 0x17, 0x88, 0xbe, 0x00, + 0xb0, 0x36, 0x27, 0x96, 0x13, 0xf7, 0xe4, 0x19, 0x82, 0x24, 0x73, 0x70, 0x2a, 0x08, 0x3e, 0xf1, + 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, + 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xcb, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, + 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x94, 0x10, 0x28, 0x33, 0xd1, 0x4d, 0xce, 0x48, 0xcc, 0xcc, 0xd3, + 0x87, 0x8b, 0x54, 0xc0, 0x43, 0xa5, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x2c, 0x63, 0x0c, + 0x08, 0x00, 0x00, 0xff, 0xff, 0xfd, 0xee, 0x81, 0x57, 0x8a, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -113,6 +128,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.ListingVaultDepositParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 if m.HardCapForMarkets != 0 { i = encodeVarintGenesis(dAtA, i, uint64(m.HardCapForMarkets)) i-- @@ -141,6 +166,8 @@ func (m *GenesisState) Size() (n int) { if m.HardCapForMarkets != 0 { n += 1 + sovGenesis(uint64(m.HardCapForMarkets)) } + l = m.ListingVaultDepositParams.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -198,6 +225,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { break } } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListingVaultDepositParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListingVaultDepositParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/protocol/x/listing/types/params.go b/protocol/x/listing/types/params.go index 2cf5960179..073654d4d7 100644 --- a/protocol/x/listing/types/params.go +++ b/protocol/x/listing/types/params.go @@ -5,7 +5,7 @@ import "github.com/dydxprotocol/v4-chain/protocol/dtypes" // DefaultParams defines the default parameters for listing vault deposits. func DefaultParams() ListingVaultDepositParams { return ListingVaultDepositParams{ - NewVaultDepositAmount: dtypes.NewIntFromUint64(10_000), + NewVaultDepositAmount: dtypes.NewIntFromUint64(10_000_000_000), // 10_000 USDC MainVaultDepositAmount: dtypes.NewIntFromUint64(0), NumBlocksToLockShares: 30 * 24 * 3600, // 30 days } diff --git a/protocol/x/vault/keeper/params.go b/protocol/x/vault/keeper/params.go index a054e9d057..3903281396 100644 --- a/protocol/x/vault/keeper/params.go +++ b/protocol/x/vault/keeper/params.go @@ -117,6 +117,20 @@ func (k Keeper) SetVaultParams( return nil } +// SetVaultStatus sets `VaultParams.Status` in state for a given vault. +func (k Keeper) SetVaultStatus( + ctx sdk.Context, + vaultId types.VaultId, + status types.VaultStatus, +) error { + vaultParams, exists := k.GetVaultParams(ctx, vaultId) + if !exists { + return types.ErrVaultParamsNotFound + } + vaultParams.Status = status + return k.SetVaultParams(ctx, vaultId, vaultParams) +} + // getVaultParamsIterator returns an iterator over all VaultParams. func (k Keeper) getVaultParamsIterator(ctx sdk.Context) storetypes.Iterator { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.VaultParamsKeyPrefix)) From 881e36a4805ee78b6f79b850b68d8a20910a0522 Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Wed, 25 Sep 2024 16:55:12 -0400 Subject: [PATCH 043/120] [OTE-829] upgrade handler for affiliates (#2332) --- .../app/testdata/default_genesis_state.json | 23 ++++++++++++++++- .../upgrades/v7.0.0/upgrade_container_test.go | 20 +++++++++++++++ .../scripts/genesis/sample_pregenesis.json | 25 +++++++++++++++++-- protocol/x/affiliates/types/genesis.go | 4 +-- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/protocol/app/testdata/default_genesis_state.json b/protocol/app/testdata/default_genesis_state.json index 48de48a5ba..0263da539b 100644 --- a/protocol/app/testdata/default_genesis_state.json +++ b/protocol/app/testdata/default_genesis_state.json @@ -15,7 +15,28 @@ }, "affiliates": { "affiliate_tiers": { - "tiers": [] + "tiers": [ + { + "req_referred_volume_quote_quantums": "0", + "req_staked_whole_coins": 0, + "taker_fee_share_ppm": 50000 + }, + { + "req_referred_volume_quote_quantums": "1000000000000", + "req_staked_whole_coins": 200, + "taker_fee_share_ppm": 100000 + }, + { + "req_referred_volume_quote_quantums": "5000000000000", + "req_staked_whole_coins": 1000, + "taker_fee_share_ppm": 125000 + }, + { + "req_referred_volume_quote_quantums": "25000000000000", + "req_staked_whole_coins": 5000, + "taker_fee_share_ppm": 150000 + } + ] } }, "auth": { diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go index e92ee609ca..e0df3171d7 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go @@ -11,6 +11,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/dtypes" "github.com/dydxprotocol/v4-chain/protocol/testing/containertest" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + affiliatestypes "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" "github.com/stretchr/testify/require" ) @@ -48,6 +49,9 @@ func preUpgradeChecks(node *containertest.Node, t *testing.T) { func postUpgradeChecks(node *containertest.Node, t *testing.T) { // Add test for your upgrade handler logic below postUpgradeVaultParamsCheck(node, t) + + // Check that the affiliates module has been initialized with the default tiers. + postUpgradeAffiliatesModuleTiersCheck(node, t) } func postUpgradeVaultParamsCheck(node *containertest.Node, t *testing.T) { @@ -96,3 +100,19 @@ func checkVaultParams( require.Equal(t, expectedStatus, vaultParamsResp.VaultParams.Status) require.Equal(t, expectedQuotingParams, vaultParamsResp.VaultParams.QuotingParams) } + +func postUpgradeAffiliatesModuleTiersCheck(node *containertest.Node, t *testing.T) { + resp, err := containertest.Query( + node, + affiliatestypes.NewQueryClient, + affiliatestypes.QueryClient.AllAffiliateTiers, + &affiliatestypes.AllAffiliateTiersRequest{}, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + affiliateTiersResp := affiliatestypes.AllAffiliateTiersResponse{} + err = proto.UnmarshalText(resp.String(), &affiliateTiersResp) + require.NoError(t, err) + require.Equal(t, affiliatestypes.DefaultAffiliateTiers, affiliateTiersResp.Tiers) +} diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index 6594f9c167..e8f7131930 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -4,7 +4,28 @@ "app_state": { "affiliates": { "affiliate_tiers": { - "tiers": [] + "tiers": [ + { + "req_referred_volume_quote_quantums": "0", + "req_staked_whole_coins": 0, + "taker_fee_share_ppm": 50000 + }, + { + "req_referred_volume_quote_quantums": "1000000000000", + "req_staked_whole_coins": 200, + "taker_fee_share_ppm": 100000 + }, + { + "req_referred_volume_quote_quantums": "5000000000000", + "req_staked_whole_coins": 1000, + "taker_fee_share_ppm": 125000 + }, + { + "req_referred_volume_quote_quantums": "25000000000000", + "req_staked_whole_coins": 5000, + "taker_fee_share_ppm": 150000 + } + ] } }, "assets": { @@ -4000,7 +4021,7 @@ ] } }, - "app_version": "5.2.1-103-g5c95dd72", + "app_version": "5.2.1-172-g351fcccd", "chain_id": "dydx-sample-1", "consensus": { "params": { diff --git a/protocol/x/affiliates/types/genesis.go b/protocol/x/affiliates/types/genesis.go index 68668b98df..0fac6ad561 100644 --- a/protocol/x/affiliates/types/genesis.go +++ b/protocol/x/affiliates/types/genesis.go @@ -3,9 +3,7 @@ package types // DefaultGenesis returns the default stats genesis state. func DefaultGenesis() *GenesisState { return &GenesisState{ - AffiliateTiers: AffiliateTiers{ - Tiers: []AffiliateTiers_Tier{}, - }, + AffiliateTiers: DefaultAffiliateTiers, } } From 10a018f4af089a1b9961f8a3b991d49c1817b3a1 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:59:49 -0400 Subject: [PATCH 044/120] [CT-1198] Add smart account and circuit break ante handler (#2325) --- protocol/lib/metrics/metric_keys.go | 4 +- protocol/x/accountplus/ante/ante.go | 299 +++++++++++ protocol/x/accountplus/ante/ante_test.go | 507 ++++++++++++++++++ .../x/accountplus/ante/circuit_breaker.go | 52 ++ .../accountplus/ante/circuit_breaker_test.go | 194 +++++++ .../authenticator/signature_authenticator.go | 5 - .../x/accountplus/keeper/authenticators.go | 13 +- protocol/x/accountplus/lib/lib.go | 43 ++ protocol/x/accountplus/types/errors.go | 7 +- 9 files changed, 1111 insertions(+), 13 deletions(-) create mode 100644 protocol/x/accountplus/ante/ante.go create mode 100644 protocol/x/accountplus/ante/ante_test.go create mode 100644 protocol/x/accountplus/ante/circuit_breaker.go create mode 100644 protocol/x/accountplus/ante/circuit_breaker_test.go create mode 100644 protocol/x/accountplus/lib/lib.go diff --git a/protocol/lib/metrics/metric_keys.go b/protocol/lib/metrics/metric_keys.go index 9146cf1ff7..c84abc2fb1 100644 --- a/protocol/lib/metrics/metric_keys.go +++ b/protocol/lib/metrics/metric_keys.go @@ -91,5 +91,7 @@ const ( EndBlockerLag = "end_blocker_lag" // Account plus - MissingRegisteredAuthenticator = "missing_registered_authenticator" + AuthenticatorDecoratorAnteHandleLatency = "authenticator_decorator_ante_handle_latency" + MissingRegisteredAuthenticator = "missing_registered_authenticator" + AuthenticatorTrackFailed = "authenticator_track_failed" ) diff --git a/protocol/x/accountplus/ante/ante.go b/protocol/x/accountplus/ante/ante.go new file mode 100644 index 0000000000..c68c53d277 --- /dev/null +++ b/protocol/x/accountplus/ante/ante.go @@ -0,0 +1,299 @@ +package ante + +import ( + "bytes" + "strconv" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + + txsigning "cosmossdk.io/x/tx/signing" + + "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" +) + +// AuthenticatorDecorator is responsible for processing authentication logic +// before transaction execution. +type AuthenticatorDecorator struct { + accountPlusKeeper *keeper.Keeper + accountKeeper authante.AccountKeeper + sigModeHandler *txsigning.HandlerMap + cdc codec.Codec +} + +// NewAuthenticatorDecorator creates a new instance of AuthenticatorDecorator with the provided parameters. +func NewAuthenticatorDecorator( + cdc codec.Codec, + accountPlusKeeper *keeper.Keeper, + accountKeeper authante.AccountKeeper, + sigModeHandler *txsigning.HandlerMap, +) AuthenticatorDecorator { + return AuthenticatorDecorator{ + accountPlusKeeper: accountPlusKeeper, + accountKeeper: accountKeeper, + sigModeHandler: sigModeHandler, + cdc: cdc, + } +} + +// AnteHandle is the authenticator ante handler responsible for processing authentication +// logic before transaction execution. +func (ad AuthenticatorDecorator) AnteHandle( + ctx sdk.Context, + tx sdk.Tx, + simulate bool, + next sdk.AnteHandler, +) (newCtx sdk.Context, err error) { + defer metrics.ModuleMeasureSince( + types.ModuleName, + metrics.AuthenticatorDecoratorAnteHandleLatency, + time.Now(), + ) + + // Make sure smart account is active. + if active := ad.accountPlusKeeper.GetIsSmartAccountActive(ctx); !active { + return ctx, types.ErrSmartAccountNotActive + } + + // Authenticators don't support manually setting the fee payer + err = ad.ValidateAuthenticatorFeePayer(tx) + if err != nil { + return ctx, err + } + + msgs := tx.GetMsgs() + if len(msgs) == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "no messages in transaction") + } + + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + // The fee payer is the first signer of the transaction. This should have been enforced by the + // ValidateAuthenticatorFeePayer. + signers, _, err := ad.cdc.GetMsgV1Signers(msgs[0]) + if err != nil { + return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "failed to get signers") + } + feePayer := sdk.AccAddress(signers[0]) + feeGranter := feeTx.FeeGranter() + fee := feeTx.GetFee() + + selectedAuthenticators, err := ad.GetSelectedAuthenticators(tx, len(msgs)) + if err != nil { + return ctx, err + } + + // tracks are used to make sure that we only write to the store after every message is successful + var tracks []func() error + + // Authenticate the accounts of all messages + for msgIndex, msg := range msgs { + signers, _, err := ad.cdc.GetMsgV1Signers(msg) + if err != nil { + return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "failed to get signers") + } + // Enforce only one signer per message + if len(signers) != 1 { + return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "messages must have exactly one signer") + } + + // Get the account corresponding to the only signer of this message. + account := sdk.AccAddress(signers[0]) + + // Get the currently selected authenticator + selectedAuthenticatorId := selectedAuthenticators[msgIndex] + selectedAuthenticator, err := ad.accountPlusKeeper.GetInitializedAuthenticatorForAccount( + ctx, + account, + selectedAuthenticatorId, + ) + if err != nil { + return ctx, + errorsmod.Wrapf( + err, + "failed to get initialized authenticator "+ + "(account = %s, authenticator id = %d, msg index = %d, msg type url = %s)", + account, + selectedAuthenticatorId, + msgIndex, + sdk.MsgTypeURL(msg), + ) + } + + // Generate the authentication request data + authenticationRequest, err := authenticator.GenerateAuthenticationRequest( + ctx, + ad.cdc, + ad.accountKeeper, + ad.sigModeHandler, + account, + feePayer, + feeGranter, + fee, + msg, + tx, + msgIndex, + simulate, + ) + if err != nil { + return ctx, + errorsmod.Wrapf( + err, + "failed to generate authentication data "+ + "(account = %s, authenticator id = %d, msg index = %d, msg type url = %s)", + account, + selectedAuthenticator.Id, + msgIndex, + sdk.MsgTypeURL(msg), + ) + } + + authenticator := selectedAuthenticator.Authenticator + stringId := strconv.FormatUint(selectedAuthenticator.Id, 10) + authenticationRequest.AuthenticatorId = stringId + + // Consume the authenticator's static gas + ctx.GasMeter().ConsumeGas(authenticator.StaticGas(), "authenticator static gas") + + // Authenticate should never modify state. That's what track is for + neverWriteCtx, _ := ctx.CacheContext() + authErr := authenticator.Authenticate(neverWriteCtx, authenticationRequest) + + // If authentication is successful, continue + if authErr == nil { + // Append the track closure to be called after every message is authenticated + // Note: pre-initialize type URL to avoid closure issues from passing a msg + // loop variable inside the closure. + currentMsgTypeURL := sdk.MsgTypeURL(msg) + tracks = append(tracks, func() error { + err := authenticator.Track(ctx, authenticationRequest) + if err != nil { + // track should not fail in normal circumstances, + // since it is intended to update track state before execution. + // If it does fail, we log the error. + metrics.IncrCounter(metrics.AuthenticatorTrackFailed, 1) + ad.accountPlusKeeper.Logger(ctx).Error( + "track failed", + "account", account, + "feePayer", feePayer, + "msg", currentMsgTypeURL, + "authenticatorId", stringId, + "error", err, + ) + + return errorsmod.Wrapf( + err, + "track failed (account = %s, authenticator id = %s, authenticator type, %s, msg index = %d)", + account, + stringId, + authenticator.Type(), + msgIndex, + ) + } + return nil + }) + } + + // If authentication failed, return an error + if authErr != nil { + return ctx, errorsmod.Wrapf( + authErr, + "authentication failed for message %d, authenticator id %d, type %s", + msgIndex, + selectedAuthenticator.Id, + selectedAuthenticator.Authenticator.Type(), + ) + } + } + + // If the transaction has been authenticated, we call Track(...) on every message + // to notify its authenticator so that it can handle any state updates. + for _, track := range tracks { + if err := track(); err != nil { + return ctx, err + } + } + + return next(ctx, tx, simulate) +} + +// ValidateAuthenticatorFeePayer enforces that the tx fee payer has not been set manually +// to an account different to the signer of the first message. This is a requirement +// for the authenticator module. +// The only user of a manually set fee payer is with fee grants, which are not +// available on dydx. +func (ad AuthenticatorDecorator) ValidateAuthenticatorFeePayer(tx sdk.Tx) error { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + // The fee payer by default is the first signer of the transaction + feePayer := feeTx.FeePayer() + + msgs := tx.GetMsgs() + if len(msgs) == 0 { + return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must contain at least one message") + } + signers, _, err := ad.cdc.GetMsgV1Signers(msgs[0]) + if err != nil { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "failed to get signers") + } + if len(signers) == 0 { + return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx message must contain at least one signer") + } + + if !bytes.Equal(feePayer, signers[0]) { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "fee payer must be the first signer") + } + return nil +} + +// GetSelectedAuthenticators retrieves the selected authenticators for the provided transaction extension +// and matches them with the number of messages in the transaction. +// If no selected authenticators are found in the extension, the function initializes the list with -1 values. +// It returns an array of selected authenticators or an error if the number of selected authenticators does not match +// the number of messages in the transaction. +func (ad AuthenticatorDecorator) GetSelectedAuthenticators( + tx sdk.Tx, + msgCount int, +) ([]uint64, error) { + extTx, ok := tx.(authante.HasExtensionOptionsTx) + if !ok { + return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a HasExtensionOptionsTx to use Authenticators") + } + + // Get the selected authenticator options from the transaction. + txOptions := lib.GetAuthenticatorExtension(extTx.GetNonCriticalExtensionOptions(), ad.cdc) + if txOptions == nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, + "Cannot get AuthenticatorTxOptions from tx") + } + // Retrieve the selected authenticators from the extension. + selectedAuthenticators := txOptions.GetSelectedAuthenticators() + + if len(selectedAuthenticators) != msgCount { + // Return an error if the number of selected authenticators does not match the number of messages. + return nil, errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "Mismatch between the number of selected authenticators and messages, "+ + "msg count %d, got %d selected authenticators", + msgCount, + len(selectedAuthenticators), + ) + } + + return selectedAuthenticators, nil +} diff --git a/protocol/x/accountplus/ante/ante_test.go b/protocol/x/accountplus/ante/ante_test.go new file mode 100644 index 0000000000..c6d7969f3f --- /dev/null +++ b/protocol/x/accountplus/ante/ante_test.go @@ -0,0 +1,507 @@ +package ante_test + +import ( + "encoding/hex" + "fmt" + "math/rand" + "os" + "testing" + "time" + + storetypes "cosmossdk.io/store/types" + tmtypes "github.com/cometbft/cometbft/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/stretchr/testify/suite" + + "github.com/dydxprotocol/v4-chain/protocol/app" + "github.com/dydxprotocol/v4-chain/protocol/app/config" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/ante" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" +) + +type AuthenticatorAnteSuite struct { + suite.Suite + + tApp *testapp.TestApp + Ctx sdk.Context + EncodingConfig app.EncodingConfig + AuthenticatorDecorator ante.AuthenticatorDecorator + TestKeys []string + TestAccAddress []sdk.AccAddress + TestPrivKeys []*secp256k1.PrivKey + HomeDir string +} + +func TestAuthenticatorAnteSuite(t *testing.T) { + suite.Run(t, new(AuthenticatorAnteSuite)) +} + +func (s *AuthenticatorAnteSuite) SetupTest() { + // Test data for authenticator signature verification + TestKeys := []string{ + "6cf5103c60c939a5f38e383b52239c5296c968579eec1c68a47d70fbf1d19159", + "0dd4d1506e18a5712080708c338eb51ecf2afdceae01e8162e890b126ac190fe", + "49006a359803f0602a7ec521df88bf5527579da79112bb71f285dd3e7d438033", + } + + s.HomeDir = fmt.Sprintf("%d", rand.Int()) + + // Set up test accounts + accounts := make([]sdk.AccountI, 0) + for _, key := range TestKeys { + bz, _ := hex.DecodeString(key) + priv := &secp256k1.PrivKey{Key: bz} + + // Add the test private keys to an array for later use + s.TestPrivKeys = append(s.TestPrivKeys, priv) + + // Generate an account address from the public key + accAddress := sdk.AccAddress(priv.PubKey().Address()) + accounts = append( + accounts, + authtypes.NewBaseAccount(accAddress, priv.PubKey(), 0, 0), + ) + + // Add the test accounts' addresses to an array for later use + s.TestAccAddress = append(s.TestAccAddress, accAddress) + } + + s.tApp = testapp.NewTestAppBuilder(s.T()).WithGenesisDocFn(func() (genesis tmtypes.GenesisDoc) { + genesis = testapp.DefaultGenesis() + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *authtypes.GenesisState) { + for _, acct := range accounts { + genesisState.Accounts = append(genesisState.Accounts, codectypes.UnsafePackAny(acct)) + } + }, + ) + return genesis + }).Build() + s.Ctx = s.tApp.InitChain() + + s.EncodingConfig = app.GetEncodingConfig() + s.AuthenticatorDecorator = ante.NewAuthenticatorDecorator( + s.tApp.App.AppCodec(), + &s.tApp.App.AccountPlusKeeper, + s.tApp.App.AccountKeeper, + s.EncodingConfig.TxConfig.SignModeHandler(), + ) + s.Ctx = s.Ctx.WithGasMeter(storetypes.NewGasMeter(1_000_000)) +} + +func (s *AuthenticatorAnteSuite) TearDownTest() { + os.RemoveAll(s.HomeDir) +} + +// TestSignatureVerificationNoAuthenticatorInStore test a non-smart account signature verification +// with no authenticator in the store +func (s *AuthenticatorAnteSuite) TestSignatureVerificationNoAuthenticatorInStore() { + bech32Prefix := config.Bech32PrefixAccAddr + coins := sdk.Coins{sdk.NewInt64Coin(constants.TestNativeTokenDenom, 2500)} + + // Create a test messages for signing + testMsg1 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[0]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + testMsg2 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + feeCoins := constants.TestFeeCoins_5Cents + + tx, err := GenTx( + s.Ctx, + s.EncodingConfig.TxConfig, + []sdk.Msg{ + testMsg1, + testMsg2, + }, + feeCoins, + 300000, + s.Ctx.ChainID(), + []uint64{6, 6}, + []uint64{0, 0}, + []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, + []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, + []uint64{0, 0}, + ) + s.Require().NoError(err) + + anteHandler := sdk.ChainAnteDecorators(s.AuthenticatorDecorator) + _, err = anteHandler(s.Ctx, tx, false) + + s.Require().Error(err, "Expected error when no authenticator is in the store") +} + +// TestSignatureVerificationWithAuthenticatorInStore test a non-smart account signature verification +// with a single authenticator in the store +func (s *AuthenticatorAnteSuite) TestSignatureVerificationWithAuthenticatorInStore() { + bech32Prefix := config.Bech32PrefixAccAddr + coins := sdk.Coins{sdk.NewInt64Coin(constants.TestNativeTokenDenom, 2500)} + + // Create a test messages for signing + testMsg1 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[0]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + testMsg2 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + feeCoins := constants.TestFeeCoins_5Cents + + id, err := s.tApp.App.AccountPlusKeeper.AddAuthenticator( + s.Ctx, + s.TestAccAddress[0], + "SignatureVerification", + s.TestPrivKeys[0].PubKey().Bytes(), + ) + s.Require().NoError(err) + s.Require().Equal(id, uint64(0), "Adding authenticator returning incorrect id") + + id, err = s.tApp.App.AccountPlusKeeper.AddAuthenticator( + s.Ctx, + s.TestAccAddress[1], + "SignatureVerification", + s.TestPrivKeys[1].PubKey().Bytes(), + ) + s.Require().NoError(err) + s.Require().Equal(id, uint64(1), "Adding authenticator returning incorrect id") + + s.tApp.App.AccountPlusKeeper.SetActiveState(s.Ctx, true) + s.Require().True( + s.tApp.App.AccountPlusKeeper.GetIsSmartAccountActive(s.Ctx), + "Expected smart account to be active", + ) + + tx, err := GenTx( + s.Ctx, + s.EncodingConfig.TxConfig, + []sdk.Msg{ + testMsg1, + testMsg2, + }, + feeCoins, + 300000, + s.Ctx.ChainID(), + []uint64{5, 6}, + []uint64{0, 0}, + []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, + []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, + []uint64{0, 1}, + ) + s.Require().NoError(err) + + anteHandler := sdk.ChainAnteDecorators(s.AuthenticatorDecorator) + _, err = anteHandler(s.Ctx, tx, false) + + s.Require().NoError(err) +} + +// TestFeePayerGasComsumption tests that the fee payer only gets charged gas for the transaction once. +func (s *AuthenticatorAnteSuite) TestFeePayerGasComsumption() { + bech32Prefix := config.Bech32PrefixAccAddr + coins := sdk.Coins{sdk.NewInt64Coin(constants.TestNativeTokenDenom, 2500)} + feeCoins := constants.TestFeeCoins_5Cents + + specifiedGasLimit := uint64(300_000) + + // Create two messages to ensure that the fee payer code path is reached twice + testMsg1 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[0]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + + testMsg2 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[0]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + + // Add a signature verification authenticator to the account + sigId, err := s.tApp.App.AccountPlusKeeper.AddAuthenticator( + s.Ctx, + s.TestAccAddress[0], + "SignatureVerification", + s.TestPrivKeys[1].PubKey().Bytes(), + ) + s.Require().NoError(err) + s.Require().Equal(sigId, uint64(0), "Adding authenticator returning incorrect id") + + s.tApp.App.AccountPlusKeeper.SetActiveState(s.Ctx, true) + s.Require().True( + s.tApp.App.AccountPlusKeeper.GetIsSmartAccountActive(s.Ctx), + "Expected smart account to be active", + ) + + tx, err := GenTx( + s.Ctx, + s.EncodingConfig.TxConfig, + []sdk.Msg{ + testMsg1, + testMsg2, + }, + feeCoins, + specifiedGasLimit, + s.Ctx.ChainID(), + []uint64{5, 5}, + []uint64{0, 0}, + []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + }, + []cryptotypes.PrivKey{ + s.TestPrivKeys[1], + }, + []uint64{sigId, sigId}, + ) + s.Require().NoError(err) + + anteHandler := sdk.ChainAnteDecorators(s.AuthenticatorDecorator) + _, err = anteHandler(s.Ctx, tx, false) + s.Require().NoError(err) +} + +func (s *AuthenticatorAnteSuite) TestSpecificAuthenticator() { + bech32Prefix := config.Bech32PrefixAccAddr + coins := sdk.Coins{sdk.NewInt64Coin(constants.TestNativeTokenDenom, 2500)} + feeCoins := constants.TestFeeCoins_5Cents + + // Create a test messages for signing + testMsg1 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + + sig1Id, err := s.tApp.App.AccountPlusKeeper.AddAuthenticator( + s.Ctx, + s.TestAccAddress[1], + "SignatureVerification", + s.TestPrivKeys[0].PubKey().Bytes(), + ) + s.Require().NoError(err) + s.Require().Equal(sig1Id, uint64(0), "Adding authenticator returning incorrect id") + + sig2Id, err := s.tApp.App.AccountPlusKeeper.AddAuthenticator( + s.Ctx, + s.TestAccAddress[1], + "SignatureVerification", + s.TestPrivKeys[1].PubKey().Bytes(), + ) + s.Require().NoError(err) + s.Require().Equal(sig2Id, uint64(1), "Adding authenticator returning incorrect id") + + s.tApp.App.AccountPlusKeeper.SetActiveState(s.Ctx, true) + s.Require().True( + s.tApp.App.AccountPlusKeeper.GetIsSmartAccountActive(s.Ctx), + "Expected smart account to be active", + ) + + testCases := map[string]struct { + name string + senderKey cryptotypes.PrivKey + signKey cryptotypes.PrivKey + selectedAuthenticator []uint64 + shouldPass bool + }{ + "Correct authenticator 0": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[0], + selectedAuthenticator: []uint64{sig1Id}, + shouldPass: true, + }, + "Correct authenticator 1": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[1], + selectedAuthenticator: []uint64{sig2Id}, + shouldPass: true, + }, + "Incorrect authenticator 0": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[0], + selectedAuthenticator: []uint64{sig2Id}, + shouldPass: false, + }, + "Incorrect authenticator 1": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[1], + selectedAuthenticator: []uint64{sig1Id}, + shouldPass: false, + }, + "Not Specified for 0": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[0], + selectedAuthenticator: []uint64{}, + shouldPass: false, + }, + "Not Specified for 1": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[1], + selectedAuthenticator: []uint64{}, + shouldPass: false, + }, + "Bad selection": { + senderKey: s.TestPrivKeys[0], + signKey: s.TestPrivKeys[0], + selectedAuthenticator: []uint64{3}, + shouldPass: false, + }, + } + + for name, tc := range testCases { + s.Run(name, func() { + tx, err := GenTx( + s.Ctx, + s.EncodingConfig.TxConfig, + []sdk.Msg{ + testMsg1, + }, + feeCoins, + 300000, + s.Ctx.ChainID(), + []uint64{6}, + []uint64{0}, + []cryptotypes.PrivKey{ + tc.senderKey, + }, + []cryptotypes.PrivKey{ + tc.signKey, + }, + tc.selectedAuthenticator, + ) + s.Require().NoError(err) + + anteHandler := sdk.ChainAnteDecorators(s.AuthenticatorDecorator) + _, err = anteHandler(s.Ctx.WithGasMeter(storetypes.NewGasMeter(300000)), tx, false) + + if tc.shouldPass { + s.Require().NoError(err, "Expected to pass but got error") + } else { + s.Require().Error(err, "Expected to fail but got no error") + } + }) + } +} + +// GenTx generates a signed mock transaction. +func GenTx( + ctx sdk.Context, + gen client.TxConfig, + msgs []sdk.Msg, + feeAmt sdk.Coins, + gas uint64, + chainID string, + accNums, accSeqs []uint64, + signers, signatures []cryptotypes.PrivKey, + selectedAuthenticators []uint64, +) (sdk.Tx, error) { + sigs := make([]signing.SignatureV2, len(signers)) + + // create a random length memo + r := rand.New(rand.NewSource(time.Now().UnixNano())) + memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) + signMode, err := authsigning.APISignModeToInternal(gen.SignModeHandler().DefaultMode()) + if err != nil { + return nil, err + } + + // 1st round: set SignatureV2 with empty signatures, to set correct + // signer infos. + for i, p := range signers { + sigs[i] = signing.SignatureV2{ + PubKey: p.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + }, + Sequence: accSeqs[i], + } + } + + baseTxBuilder := gen.NewTxBuilder() + + txBuilder, ok := baseTxBuilder.(authtx.ExtensionOptionsTxBuilder) + if !ok { + return nil, fmt.Errorf("expected authtx.ExtensionOptionsTxBuilder, got %T", baseTxBuilder) + } + if len(selectedAuthenticators) > 0 { + value, err := codectypes.NewAnyWithValue(&types.TxExtension{ + SelectedAuthenticators: selectedAuthenticators, + }) + if err != nil { + return nil, err + } + txBuilder.SetNonCriticalExtensionOptions(value) + } + + err = txBuilder.SetMsgs(msgs...) + if err != nil { + return nil, err + } + err = txBuilder.SetSignatures(sigs...) + if err != nil { + return nil, err + } + txBuilder.SetMemo(memo) + txBuilder.SetFeeAmount(feeAmt) + txBuilder.SetGasLimit(gas) + + // 2nd round: once all signer infos are set, every signer can sign. + for i, p := range signatures { + signerData := authsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + signBytes, err := authsigning.GetSignBytesAdapter( + ctx, gen.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) + if err != nil { + panic(err) + } + + sig, err := p.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i].Data.(*signing.SingleSignatureData).Signature = sig + err = txBuilder.SetSignatures(sigs...) + if err != nil { + panic(err) + } + } + + return txBuilder.GetTx(), nil +} diff --git a/protocol/x/accountplus/ante/circuit_breaker.go b/protocol/x/accountplus/ante/circuit_breaker.go new file mode 100644 index 0000000000..549461847a --- /dev/null +++ b/protocol/x/accountplus/ante/circuit_breaker.go @@ -0,0 +1,52 @@ +package ante + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" +) + +// CircuitBreakerDecorator routes transactions through appropriate ante handlers based on +// the existence of `TxExtension`. +type CircuitBreakerDecorator struct { + cdc codec.BinaryCodec + authenticatorAnteHandlerFlow sdk.AnteHandler + originalAnteHandlerFlow sdk.AnteHandler +} + +// NewCircuitBreakerDecorator creates a new instance of CircuitBreakerDecorator with the provided parameters. +func NewCircuitBreakerDecorator( + cdc codec.BinaryCodec, + auth sdk.AnteHandler, + classic sdk.AnteHandler, +) CircuitBreakerDecorator { + return CircuitBreakerDecorator{ + cdc: cdc, + authenticatorAnteHandlerFlow: auth, + originalAnteHandlerFlow: classic, + } +} + +// AnteHandle checks if a tx is a smart account tx and routes it through the correct series of ante handlers. +// +// Note that whether or not to use the new authenticator flow is determined by the presence of the `TxExtension`. +// This is different from the Osmosis's implementation, which falls back to the original flow if +// smart account is disabled. +// The reason for this is because only minimal validation is done on resting maker orders when they get matched +// and this approach mitigates an issue for maker orders when smart account gets disabled through governance. +func (ad CircuitBreakerDecorator) AnteHandle( + ctx sdk.Context, + tx sdk.Tx, + simulate bool, + next sdk.AnteHandler, +) (newCtx sdk.Context, err error) { + // Check that the authenticator flow is active + if specified, _ := lib.HasSelectedAuthenticatorTxExtensionSpecified(tx, ad.cdc); specified { + // Return and call the AnteHandle function on all the authenticator decorators. + return ad.authenticatorAnteHandlerFlow(ctx, tx, simulate) + } + + // Return and call the AnteHandle function on all the original decorators. + return ad.originalAnteHandlerFlow(ctx, tx, simulate) +} diff --git a/protocol/x/accountplus/ante/circuit_breaker_test.go b/protocol/x/accountplus/ante/circuit_breaker_test.go new file mode 100644 index 0000000000..08ac7e7a81 --- /dev/null +++ b/protocol/x/accountplus/ante/circuit_breaker_test.go @@ -0,0 +1,194 @@ +package ante_test + +import ( + "encoding/hex" + "fmt" + "math/rand" + "os" + "testing" + + "github.com/cometbft/cometbft/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/dydxprotocol/v4-chain/protocol/app/config" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + + "github.com/stretchr/testify/suite" + + "github.com/dydxprotocol/v4-chain/protocol/app" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/ante" +) + +// AuthenticatorCircuitBreakerAnteSuite is a test suite for the authenticator and CircuitBreaker AnteDecorator. +type AuthenticatorCircuitBreakerAnteSuite struct { + suite.Suite + + tApp *testapp.TestApp + Ctx sdk.Context + EncodingConfig app.EncodingConfig + AuthenticatorDecorator ante.AuthenticatorDecorator + TestKeys []string + TestAccAddress []sdk.AccAddress + TestPrivKeys []*secp256k1.PrivKey + HomeDir string +} + +// TestAuthenticatorCircuitBreakerAnteSuite runs the test suite for the authenticator and CircuitBreaker AnteDecorator. +func TestAuthenticatorCircuitBreakerAnteSuite(t *testing.T) { + suite.Run(t, new(AuthenticatorCircuitBreakerAnteSuite)) +} + +// SetupTest initializes the test data and prepares the test environment. +func (s *AuthenticatorCircuitBreakerAnteSuite) SetupTest() { + // Test data for authenticator signature verification + TestKeys := []string{ + "6cf5103c60c939a5f38e383b52239c5296c968579eec1c68a47d70fbf1d19159", + "0dd4d1506e18a5712080708c338eb51ecf2afdceae01e8162e890b126ac190fe", + "49006a359803f0602a7ec521df88bf5527579da79112bb71f285dd3e7d438033", + "05d2f57e30fb44835da1cad5274cefd4c80f6652c425fb9e6cc9c6749126497c", + "f98d0b79c0cc9805b905bfc5104f31293a270e60c6fc613a037eeb484fddb974", + } + + // Set up test accounts + accounts := make([]sdk.AccountI, 0) + for _, key := range TestKeys { + bz, _ := hex.DecodeString(key) + priv := &secp256k1.PrivKey{Key: bz} + + // Add the test private keys to an array for later use + s.TestPrivKeys = append(s.TestPrivKeys, priv) + + // Generate an account address from the public key + accAddress := sdk.AccAddress(priv.PubKey().Address()) + accounts = append( + accounts, + authtypes.NewBaseAccount(accAddress, priv.PubKey(), 0, 0), + ) + + // Add the test accounts' addresses to an array for later use + s.TestAccAddress = append(s.TestAccAddress, accAddress) + } + + // Initialize the dydx application + s.HomeDir = fmt.Sprintf("%d", rand.Int()) + s.tApp = testapp.NewTestAppBuilder(s.T()).WithGenesisDocFn(func() (genesis types.GenesisDoc) { + genesis = testapp.DefaultGenesis() + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *authtypes.GenesisState) { + for _, acct := range accounts { + genesisState.Accounts = append(genesisState.Accounts, codectypes.UnsafePackAny(acct)) + } + }, + ) + return genesis + }).Build() + s.Ctx = s.tApp.InitChain() + + s.EncodingConfig = app.GetEncodingConfig() +} + +func (s *AuthenticatorCircuitBreakerAnteSuite) TearDownTest() { + os.RemoveAll(s.HomeDir) +} + +// MockAnteDecorator used to test the CircuitBreaker flow +type MockAnteDecorator struct { + Called int +} + +// AnteHandle increments the ctx.Priority() differently based on what flow is active +func (m MockAnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler, +) (newCtx sdk.Context, err error) { + prio := ctx.Priority() + + if m.Called == 1 { + return ctx.WithPriority(prio + 1), nil + } else { + return ctx.WithPriority(prio + 2), nil + } +} + +// TestCircuitBreakerAnte verifies that the CircuitBreaker AnteDecorator functions correctly. +func (s *AuthenticatorCircuitBreakerAnteSuite) TestCircuitBreakerAnte() { + bech32Prefix := config.Bech32PrefixAccAddr + coins := sdk.Coins{sdk.NewInt64Coin(constants.TestNativeTokenDenom, 2500)} + + // Create test messages for signing + testMsg1 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[0]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + testMsg2 := &banktypes.MsgSend{ + FromAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + ToAddress: sdk.MustBech32ifyAddressBytes(bech32Prefix, s.TestAccAddress[1]), + Amount: coins, + } + feeCoins := constants.TestFeeCoins_5Cents + + // Generate a test transaction + tx, _ := GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ + testMsg1, + testMsg2, + }, feeCoins, 300000, "", []uint64{0, 0}, []uint64{0, 0}, []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, []uint64{}) + + mockTestClassic := MockAnteDecorator{Called: 1} + mockTestAuthenticator := MockAnteDecorator{Called: 0} + + // Create a CircuitBreaker AnteDecorator + cbd := ante.NewCircuitBreakerDecorator( + s.tApp.App.AppCodec(), + sdk.ChainAnteDecorators(mockTestAuthenticator), + sdk.ChainAnteDecorators(mockTestClassic), + ) + anteHandler := sdk.ChainAnteDecorators(cbd) + + // Deactivate smart accounts + params := s.tApp.App.AccountPlusKeeper.GetParams(s.Ctx) + params.IsSmartAccountActive = false + s.tApp.App.AccountPlusKeeper.SetParams(s.Ctx, params) + + // Here we test when smart accounts are deactivated + ctx, err := anteHandler(s.Ctx, tx, false) + s.Require().NoError(err) + s.Require().Equal(int64(1), ctx.Priority(), "Should have disabled the full authentication flow") + + // Reactivate smart accounts + params = s.tApp.App.AccountPlusKeeper.GetParams(ctx) + params.IsSmartAccountActive = true + s.tApp.App.AccountPlusKeeper.SetParams(ctx, params) + + // Here we test when smart accounts are active and there is not selected authenticator + ctx, err = anteHandler(ctx, tx, false) + s.Require().Equal(int64(2), ctx.Priority(), "Will only go this way when a TxExtension is not included in the tx") + s.Require().NoError(err) + + // Generate a test transaction with a selected authenticator + tx, _ = GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ + testMsg1, + testMsg2, + }, feeCoins, 300000, "", []uint64{0, 0}, []uint64{0, 0}, []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, []cryptotypes.PrivKey{ + s.TestPrivKeys[0], + s.TestPrivKeys[1], + }, []uint64{1}) + + // Test is smart accounts are active and the authenticator flow is selected + ctx, err = anteHandler(ctx, tx, false) + s.Require().NoError(err) + s.Require().Equal(int64(4), ctx.Priority(), "Should have used the full authentication flow") +} diff --git a/protocol/x/accountplus/authenticator/signature_authenticator.go b/protocol/x/accountplus/authenticator/signature_authenticator.go index de051ad2b9..63a00bd3f6 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator.go @@ -55,11 +55,6 @@ func (sva SignatureVerification) Initialize(config []byte) (Authenticator, error // Authenticate takes a SignaturesVerificationData struct and validates // each signer and signature using signature verification func (sva SignatureVerification) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { - // First consume gas for verifying the signature - params := sva.ak.GetParams(ctx) - ctx.GasMeter().ConsumeGas(params.SigVerifyCostSecp256k1, "secp256k1 signature verification") - // after gas consumption continue to verify signatures - if request.Simulate || ctx.IsReCheckTx() { return nil } diff --git a/protocol/x/accountplus/keeper/authenticators.go b/protocol/x/accountplus/keeper/authenticators.go index 69c7599f57..2ecbeb7dff 100644 --- a/protocol/x/accountplus/keeper/authenticators.go +++ b/protocol/x/accountplus/keeper/authenticators.go @@ -160,13 +160,14 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( "account asscoicated authenticator not registered in manager", "type", authenticatorFromStore.Type, "id", selectedAuthenticator, + "account", account.String(), ) return authenticator.InitializedAuthenticator{}, errors.Wrapf( sdkerrors.ErrLogic, - "authenticator id %d failed to initialize, authenticator type %s not registered in manager", - selectedAuthenticator, authenticatorFromStore.Type, + "authenticator id %d failed to initialize for account %s, authenticator type %s not registered in manager", + selectedAuthenticator, account.String(), authenticatorFromStore.Type, ) } // Ensure that initialization of each authenticator works as expected @@ -177,16 +178,16 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( return authenticator.InitializedAuthenticator{}, errors.Wrapf( err, - "authenticator %d with type %s failed to initialize", - selectedAuthenticator, authenticatorFromStore.Type, + "authenticator %d with type %s failed to initialize for account %s", + selectedAuthenticator, authenticatorFromStore.Type, account.String(), ) } if initializedAuthenticator == nil { return authenticator.InitializedAuthenticator{}, errors.Wrapf( types.ErrInitializingAuthenticator, - "authenticator.Initialize returned nil for %d with type %s", - selectedAuthenticator, authenticatorFromStore.Type, + "authenticator.Initialize returned nil for %d with type %s for account %s", + selectedAuthenticator, authenticatorFromStore.Type, account.String(), ) } diff --git a/protocol/x/accountplus/lib/lib.go b/protocol/x/accountplus/lib/lib.go new file mode 100644 index 0000000000..9a8a04ae8d --- /dev/null +++ b/protocol/x/accountplus/lib/lib.go @@ -0,0 +1,43 @@ +package lib + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" +) + +// HasSelectedAuthenticatorTxExtensionSpecified checks to see if the transaction has the correct +// extension, it returns false if we continue to the authenticator flow. +func HasSelectedAuthenticatorTxExtensionSpecified( + tx sdk.Tx, + cdc codec.BinaryCodec, +) (bool, types.AuthenticatorTxOptions) { + extTx, ok := tx.(authante.HasExtensionOptionsTx) + if !ok { + return false, nil + } + + // Get the selected authenticator options from the transaction. + txOptions := GetAuthenticatorExtension(extTx.GetNonCriticalExtensionOptions(), cdc) + + // Check if authenticator transaction options are present and there is at least 1 selected. + if txOptions == nil || len(txOptions.GetSelectedAuthenticators()) < 1 { + return false, nil + } + + return true, txOptions +} + +// GetAuthenticatorExtension unpacks the extension for the transaction. +func GetAuthenticatorExtension(exts []*codectypes.Any, cdc codec.BinaryCodec) types.AuthenticatorTxOptions { + for _, ext := range exts { + var authExtension types.AuthenticatorTxOptions + err := cdc.UnpackAny(ext, &authExtension) + if err == nil { + return authExtension + } + } + return nil +} diff --git a/protocol/x/accountplus/types/errors.go b/protocol/x/accountplus/types/errors.go index 54a23b0e51..861e5925e0 100644 --- a/protocol/x/accountplus/types/errors.go +++ b/protocol/x/accountplus/types/errors.go @@ -18,9 +18,14 @@ var ( 3, "Authenticator data exceeds maximum length", ) - ErrInitializingAuthenticator = errorsmod.Register( + ErrSmartAccountNotActive = errorsmod.Register( ModuleName, 4, + "Smart account is not active", + ) + ErrInitializingAuthenticator = errorsmod.Register( + ModuleName, + 5, "Error initializing authenticator", ) ) From 647395120b486316f6e11a91c3775eb0d827db42 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Thu, 26 Sep 2024 11:43:27 -0400 Subject: [PATCH 045/120] [OTE-823] Fix FNS onchain events staging + retrieval logic (#2318) --- protocol/app/app.go | 1 + protocol/app/flags/flags.go | 4 ---- protocol/app/flags/flags_test.go | 15 +++++++----- .../streaming/full_node_streaming_manager.go | 23 +++++++++++++++---- protocol/x/clob/module.go | 10 ++++++++ 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/protocol/app/app.go b/protocol/app/app.go index 0528e2b17c..aad83efdcd 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -2100,6 +2100,7 @@ func getFullNodeStreamingManagerFromOptions( appFlags.GrpcStreamingMaxChannelBufferSize, appFlags.FullNodeStreamingSnapshotInterval, streamingManagerTransientStoreKey, + cdc, ) // Start websocket server. diff --git a/protocol/app/flags/flags.go b/protocol/app/flags/flags.go index cb1715ba62..9a49d4c15c 100644 --- a/protocol/app/flags/flags.go +++ b/protocol/app/flags/flags.go @@ -163,10 +163,6 @@ func (f *Flags) Validate() error { // Grpc streaming if f.GrpcStreamingEnabled { - if f.OptimisticExecutionEnabled { - // TODO(OTE-456): Finish gRPC streaming x OE integration. - return fmt.Errorf("grpc streaming cannot be enabled together with optimistic execution") - } if !f.GrpcEnable { return fmt.Errorf("grpc.enable must be set to true - grpc streaming requires gRPC server") } diff --git a/protocol/app/flags/flags_test.go b/protocol/app/flags/flags_test.go index 50e3a32c72..0ad03872fa 100644 --- a/protocol/app/flags/flags_test.go +++ b/protocol/app/flags/flags_test.go @@ -113,14 +113,17 @@ func TestValidate(t *testing.T) { OptimisticExecutionEnabled: true, }, }, - "failure - optimistic execution cannot be enabled with gRPC streaming": { + "success - optimistic execution canbe enabled with gRPC streaming": { flags: flags.Flags{ - NonValidatingFullNode: false, - GrpcEnable: true, - GrpcStreamingEnabled: true, - OptimisticExecutionEnabled: true, + NonValidatingFullNode: false, + GrpcEnable: true, + GrpcStreamingEnabled: true, + OptimisticExecutionEnabled: true, + GrpcStreamingMaxBatchSize: 2000, + GrpcStreamingFlushIntervalMs: 100, + GrpcStreamingMaxChannelBufferSize: 2000, + WebsocketStreamingPort: 8989, }, - expectedErr: fmt.Errorf("grpc streaming cannot be enabled together with optimistic execution"), }, "failure - gRPC disabled": { flags: flags.Flags{ diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index 3b3cab68ad..c43a254e78 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -13,6 +13,7 @@ import ( "cosmossdk.io/log" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ante_types "github.com/dydxprotocol/v4-chain/protocol/app/ante/types" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" @@ -27,6 +28,7 @@ var _ types.FullNodeStreamingManager = (*FullNodeStreamingManagerImpl)(nil) type FullNodeStreamingManagerImpl struct { sync.Mutex + cdc codec.BinaryCodec logger log.Logger // orderbookSubscriptions maps subscription IDs to their respective orderbook subscriptions. @@ -95,6 +97,7 @@ func NewFullNodeStreamingManager( maxSubscriptionChannelSize uint32, snapshotBlockInterval uint32, streamingManagerTransientStoreKey storetypes.StoreKey, + cdc codec.BinaryCodec, ) *FullNodeStreamingManagerImpl { fullNodeStreamingManager := &FullNodeStreamingManagerImpl{ logger: logger, @@ -113,6 +116,7 @@ func NewFullNodeStreamingManager( snapshotBlockInterval: snapshotBlockInterval, streamingManagerTransientStoreKey: streamingManagerTransientStoreKey, + cdc: cdc, } // Start the goroutine for pushing order updates through. @@ -391,6 +395,7 @@ func (sm *FullNodeStreamingManagerImpl) StageFinalizeBlockSubaccountUpdate( ctx sdk.Context, subaccountUpdate satypes.StreamSubaccountUpdate, ) { + lib.AssertDeliverTxMode(ctx) stagedEvent := clobtypes.StagedFinalizeBlockEvent{ Event: &clobtypes.StagedFinalizeBlockEvent_SubaccountUpdate{ SubaccountUpdate: &subaccountUpdate, @@ -398,7 +403,7 @@ func (sm *FullNodeStreamingManagerImpl) StageFinalizeBlockSubaccountUpdate( } sm.stageFinalizeBlockEvent( ctx, - clobtypes.Amino.MustMarshal(stagedEvent), + sm.cdc.MustMarshal(&stagedEvent), ) } @@ -411,25 +416,30 @@ func (sm *FullNodeStreamingManagerImpl) StageFinalizeBlockFill( ctx sdk.Context, fill clobtypes.StreamOrderbookFill, ) { + lib.AssertDeliverTxMode(ctx) stagedEvent := clobtypes.StagedFinalizeBlockEvent{ Event: &clobtypes.StagedFinalizeBlockEvent_OrderFill{ OrderFill: &fill, }, } + sm.stageFinalizeBlockEvent( ctx, - clobtypes.Amino.MustMarshal(stagedEvent), + sm.cdc.MustMarshal(&stagedEvent), ) } -func getStagedFinalizeBlockEvents(store storetypes.KVStore) []clobtypes.StagedFinalizeBlockEvent { +func getStagedFinalizeBlockEventsFromStore( + store storetypes.KVStore, + cdc codec.BinaryCodec, +) []clobtypes.StagedFinalizeBlockEvent { count := getStagedEventsCount(store) events := make([]clobtypes.StagedFinalizeBlockEvent, count) store = prefix.NewStore(store, []byte(StagedEventsKeyPrefix)) for i := uint32(0); i < count; i++ { var event clobtypes.StagedFinalizeBlockEvent bytes := store.Get(lib.Uint32ToKey(i)) - clobtypes.Amino.MustUnmarshal(bytes, &event) + cdc.MustUnmarshal(bytes, &event) events[i] = event } return events @@ -441,7 +451,7 @@ func (sm *FullNodeStreamingManagerImpl) GetStagedFinalizeBlockEvents( ) []clobtypes.StagedFinalizeBlockEvent { noGasCtx := ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) store := noGasCtx.TransientStore(sm.streamingManagerTransientStoreKey) - return getStagedFinalizeBlockEvents(store) + return getStagedFinalizeBlockEventsFromStore(store, sm.cdc) } func (sm *FullNodeStreamingManagerImpl) stageFinalizeBlockEvent( @@ -889,6 +899,9 @@ func (sm *FullNodeStreamingManagerImpl) StreamBatchUpdatesAfterFinalizeBlock( orderBookUpdatesToSyncLocalOpsQueue *clobtypes.OffchainUpdates, perpetualIdToClobPairId map[uint32][]clobtypes.ClobPairId, ) { + // Prevent gas metering from state read. + ctx = ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) + finalizedFills, finalizedSubaccountUpdates := sm.getStagedEventsFromFinalizeBlock(ctx) orderbookStreamUpdates, orderbookClobPairIds := getStreamUpdatesFromOffchainUpdates( diff --git a/protocol/x/clob/module.go b/protocol/x/clob/module.go index 2b61ed37c7..0e06d7e035 100644 --- a/protocol/x/clob/module.go +++ b/protocol/x/clob/module.go @@ -177,6 +177,16 @@ func (am AppModule) PreBlock(ctx context.Context) (appmodule.ResponsePreBlock, e }, nil } +// BeginBlock executes all ABCI BeginBlock logic respective to the clob module. +func (am AppModule) Precommit(ctx context.Context) error { + defer telemetry.ModuleMeasureSince(am.Name(), time.Now(), telemetry.MetricKeyPrecommiter) + Precommit( + lib.UnwrapSDKContext(ctx, types.ModuleName), + *am.keeper, + ) + return nil +} + // BeginBlock executes all ABCI BeginBlock logic respective to the clob module. func (am AppModule) BeginBlock(ctx context.Context) error { defer telemetry.ModuleMeasureSince(am.Name(), time.Now(), telemetry.MetricKeyBeginBlocker) From adb799d9f0b57e10c9189001e56839169fa0b1de Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Thu, 26 Sep 2024 13:47:47 -0400 Subject: [PATCH 046/120] Add OE Abort rate test flag (#2366) --- protocol/app/app.go | 14 +++++++++++++- protocol/app/flags/flags.go | 28 ++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/protocol/app/app.go b/protocol/app/app.go index aad83efdcd..f3cbff3f6b 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -3,6 +3,7 @@ package app import ( "context" "encoding/json" + "fmt" "io" "math/big" "net/http" @@ -33,6 +34,7 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/baseapp/oe" "github.com/cosmos/cosmos-sdk/client" cosmosflags "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" @@ -413,7 +415,17 @@ func New( // Enable optimistic block execution. if appFlags.OptimisticExecutionEnabled { logger.Info("optimistic execution is enabled.") - baseAppOptions = append(baseAppOptions, baseapp.SetOptimisticExecution()) + if appFlags.OptimisticExecutionTestAbortRate > 0 { + logger.Warn(fmt.Sprintf( + "Test flag optimistic-execution-test-abort-rate is set: %v\n", + appFlags.OptimisticExecutionTestAbortRate, + )) + } + baseAppOptions = append( + baseAppOptions, + baseapp.SetOptimisticExecution( + oe.WithAbortRate(int(appFlags.OptimisticExecutionTestAbortRate)), + )) } bApp := baseapp.NewBaseApp(appconstants.AppName, logger, db, txConfig.TxDecoder(), baseAppOptions...) diff --git a/protocol/app/flags/flags.go b/protocol/app/flags/flags.go index 9a49d4c15c..aadc805696 100644 --- a/protocol/app/flags/flags.go +++ b/protocol/app/flags/flags.go @@ -31,7 +31,8 @@ type Flags struct { VEOracleEnabled bool // Slinky Vote Extensions // Optimistic block execution - OptimisticExecutionEnabled bool + OptimisticExecutionEnabled bool + OptimisticExecutionTestAbortRate uint16 } // List of CLI flags. @@ -58,7 +59,8 @@ const ( VEOracleEnabled = "slinky-vote-extension-oracle-enabled" // Enable optimistic block execution. - OptimisticExecutionEnabled = "optimistic-execution-enabled" + OptimisticExecutionEnabled = "optimistic-execution-enabled" + OptimisticExecutionTestAbortRate = "optimistic-execution-test-abort-rate" ) // Default values. @@ -76,8 +78,10 @@ const ( DefaultWebsocketStreamingPort = 9092 DefaultFullNodeStreamingSnapshotInterval = 0 - DefaultVEOracleEnabled = true - DefaultOptimisticExecutionEnabled = false + DefaultVEOracleEnabled = true + + DefaultOptimisticExecutionEnabled = false + DefaultOptimisticExecutionTestAbortRate = 0 ) // AddFlagsToCmd adds flags to app initialization. @@ -152,6 +156,11 @@ func AddFlagsToCmd(cmd *cobra.Command) { DefaultOptimisticExecutionEnabled, "Whether to enable optimistic block execution", ) + cmd.Flags().Uint16( + OptimisticExecutionTestAbortRate, + DefaultOptimisticExecutionTestAbortRate, + "[Test only] Abort rate for optimistic execution", + ) } // Validate checks that the flags are valid. @@ -210,8 +219,9 @@ func GetFlagValuesFromOptions( WebsocketStreamingPort: DefaultWebsocketStreamingPort, FullNodeStreamingSnapshotInterval: DefaultFullNodeStreamingSnapshotInterval, - VEOracleEnabled: true, - OptimisticExecutionEnabled: DefaultOptimisticExecutionEnabled, + VEOracleEnabled: true, + OptimisticExecutionEnabled: DefaultOptimisticExecutionEnabled, + OptimisticExecutionTestAbortRate: DefaultOptimisticExecutionTestAbortRate, } // Populate the flags if they exist. @@ -304,5 +314,11 @@ func GetFlagValuesFromOptions( result.OptimisticExecutionEnabled = v } } + + if option := appOpts.Get(OptimisticExecutionTestAbortRate); option != nil { + if v, err := cast.ToUint16E(option); err == nil { + result.OptimisticExecutionTestAbortRate = v + } + } return result } From ce662f2b1a33475b5de0bb2f901e0a9b993de0a4 Mon Sep 17 00:00:00 2001 From: shrenujb <98204323+shrenujb@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:24:05 -0400 Subject: [PATCH 047/120] [TRA-617] Fix calculation for atomic resolution (#2360) Signed-off-by: Shrenuj Bansal --- protocol/x/listing/keeper/listing.go | 5 ++++- protocol/x/listing/keeper/listing_test.go | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 3141933630..82d190620d 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -148,7 +148,10 @@ func (k Keeper) CreatePerpetual( } // calculate atomic resolution from reference price - atomicResolution := types.ResolutionOffset - int32(math.Floor(math.Log10(float64(metadata.ReferencePrice)))) + // atomic resolution = -6 - (log10(referencePrice) - decimals) + atomicResolution := types.ResolutionOffset - + (int32(math.Floor(math.Log10(float64(metadata.ReferencePrice)))) - + int32(marketMapDetails.Ticker.Decimals)) // Create a new perpetual perpetual, err := k.PerpetualsKeeper.CreatePerpetual( diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index 4678a1bc7e..052172c0f0 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -152,7 +152,7 @@ func TestCreatePerpetual(t *testing.T) { market := marketmaptypes.Market{ Ticker: marketmaptypes.Ticker{ CurrencyPair: oracletypes.CurrencyPair{Base: "TEST", Quote: "USD"}, - Decimals: 6, + Decimals: 10, MinProviderCount: 2, Enabled: false, Metadata_JSON: string(dydxMetadata), @@ -185,8 +185,8 @@ func TestCreatePerpetual(t *testing.T) { require.Equal(t, uint32(10), perpetual.GetId()) require.Equal(t, marketId, perpetual.Params.MarketId) require.Equal(t, tc.ticker, perpetual.Params.Ticker) - // Expected resolution = -6 - Floor(log10(1000000000)) = -15 - require.Equal(t, int32(-15), perpetual.Params.AtomicResolution) + // Expected resolution = -6 - (Floor(log10(1000000000))-10) = -5 + require.Equal(t, int32(-5), perpetual.Params.AtomicResolution) require.Equal(t, int32(types.DefaultFundingPpm), perpetual.Params.DefaultFundingPpm) require.Equal(t, uint32(types.LiquidityTier_Isolated), perpetual.Params.LiquidityTier) require.Equal( From a97c503ac3f3beb3ca345b8940c0ffaf547ec50d Mon Sep 17 00:00:00 2001 From: shrenujb <98204323+shrenujb@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:06:35 -0400 Subject: [PATCH 048/120] Add a cli method for vault withdrawal (#2369) Signed-off-by: Shrenuj Bansal --- protocol/x/vault/client/cli/tx.go | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/protocol/x/vault/client/cli/tx.go b/protocol/x/vault/client/cli/tx.go index 573ef5034c..76fc58986e 100644 --- a/protocol/x/vault/client/cli/tx.go +++ b/protocol/x/vault/client/cli/tx.go @@ -30,6 +30,7 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdSetVaultParams()) cmd.AddCommand(CmdAllocateToVault()) cmd.AddCommand(CmdRetrieveFromVault()) + cmd.AddCommand(CmdWithdrawFromMegavault()) return cmd } @@ -243,3 +244,54 @@ func CmdRetrieveFromVault() *cobra.Command { return cmd } + +func CmdWithdrawFromMegavault() *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw-from-megavault [withdrawer_owner] [withdrawer_number] [shares] [min_quote_quantums]", + Short: "Broadcast message WithdrawFromMegavault", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + // Parse withdrawer owner and number + withdrawerOwner := args[0] + withdrawerNumber, err := cast.ToUint32E(args[1]) + if err != nil { + return err + } + + // Parse shares. + shares, err := cast.ToUint64E(args[2]) + if err != nil { + return err + } + + // Parse min quote quantums. + minQuoteQuantums, err := cast.ToUint64E(args[3]) + if err != nil { + return err + } + + // Create MsgWithdrawFromMegavault. + msg := &types.MsgWithdrawFromMegavault{ + SubaccountId: satypes.SubaccountId{ + Owner: withdrawerOwner, + Number: withdrawerNumber, + }, + Shares: types.NumShares{NumShares: dtypes.NewIntFromUint64(shares)}, + MinQuoteQuantums: dtypes.NewIntFromUint64(minQuoteQuantums), + } + + // Broadcast or generate the transaction. + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + // Add the necessary flags. + flags.AddTxFlagsToCmd(cmd) + + return cmd +} From 85ec697e20704ffaf4ec61a8d61f41f0c3c202fd Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Thu, 26 Sep 2024 18:52:44 -0400 Subject: [PATCH 049/120] [OTE-839] add query for unconditional revshare (#2380) --- .../dydxprotocol/revshare/query.lcd.ts | 10 +- .../dydxprotocol/revshare/query.rpc.Query.ts | 16 +- .../codegen/dydxprotocol/revshare/query.ts | 97 ++++- .../dydxprotocol/revshare/tx.rpc.msg.ts | 2 +- proto/dydxprotocol/revshare/query.proto | 17 +- proto/dydxprotocol/revshare/tx.proto | 2 +- protocol/x/revshare/client/cli/query.go | 1 + .../x/revshare/client/cli/query_params.go | 23 + .../grpc_query_unconditional_revshare.go | 21 + .../grpc_query_unconditional_revshare_test.go | 58 +++ protocol/x/revshare/types/query.pb.go | 393 ++++++++++++++++-- protocol/x/revshare/types/query.pb.gw.go | 65 +++ protocol/x/revshare/types/tx.pb.go | 4 +- 13 files changed, 673 insertions(+), 36 deletions(-) create mode 100644 protocol/x/revshare/keeper/grpc_query_unconditional_revshare.go create mode 100644 protocol/x/revshare/keeper/grpc_query_unconditional_revshare_test.go diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.lcd.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.lcd.ts index d79b8de832..7f45b52cc1 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.lcd.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.lcd.ts @@ -1,5 +1,5 @@ import { LCDClient } from "@osmonauts/lcd"; -import { QueryMarketMapperRevenueShareParams, QueryMarketMapperRevenueShareParamsResponseSDKType, QueryMarketMapperRevShareDetails, QueryMarketMapperRevShareDetailsResponseSDKType } from "./query"; +import { QueryMarketMapperRevenueShareParams, QueryMarketMapperRevenueShareParamsResponseSDKType, QueryMarketMapperRevShareDetails, QueryMarketMapperRevShareDetailsResponseSDKType, QueryUnconditionalRevShareConfig, QueryUnconditionalRevShareConfigResponseSDKType } from "./query"; export class LCDQueryClient { req: LCDClient; @@ -11,6 +11,7 @@ export class LCDQueryClient { this.req = requestClient; this.marketMapperRevenueShareParams = this.marketMapperRevenueShareParams.bind(this); this.marketMapperRevShareDetails = this.marketMapperRevShareDetails.bind(this); + this.unconditionalRevShareConfig = this.unconditionalRevShareConfig.bind(this); } /* MarketMapperRevenueShareParams queries the revenue share params for the market mapper */ @@ -27,5 +28,12 @@ export class LCDQueryClient { const endpoint = `dydxprotocol/revshare/market_mapper_rev_share_details/${params.marketId}`; return await this.req.get(endpoint); } + /* Queries unconditional revenue share config */ + + + async unconditionalRevShareConfig(_params: QueryUnconditionalRevShareConfig = {}): Promise { + const endpoint = `dydxprotocol/revshare/unconditional_rev_share`; + return await this.req.get(endpoint); + } } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.rpc.Query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.rpc.Query.ts index 751bf9f86f..633f6fc015 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.rpc.Query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.rpc.Query.ts @@ -1,7 +1,7 @@ import { Rpc } from "../../helpers"; import * as _m0 from "protobufjs/minimal"; import { QueryClient, createProtobufRpcClient } from "@cosmjs/stargate"; -import { QueryMarketMapperRevenueShareParams, QueryMarketMapperRevenueShareParamsResponse, QueryMarketMapperRevShareDetails, QueryMarketMapperRevShareDetailsResponse } from "./query"; +import { QueryMarketMapperRevenueShareParams, QueryMarketMapperRevenueShareParamsResponse, QueryMarketMapperRevShareDetails, QueryMarketMapperRevShareDetailsResponse, QueryUnconditionalRevShareConfig, QueryUnconditionalRevShareConfigResponse } from "./query"; /** Query defines the gRPC querier service. */ export interface Query { @@ -13,6 +13,9 @@ export interface Query { /** Queries market mapper revenue share details for a specific market */ marketMapperRevShareDetails(request: QueryMarketMapperRevShareDetails): Promise; + /** Queries unconditional revenue share config */ + + unconditionalRevShareConfig(request?: QueryUnconditionalRevShareConfig): Promise; } export class QueryClientImpl implements Query { private readonly rpc: Rpc; @@ -21,6 +24,7 @@ export class QueryClientImpl implements Query { this.rpc = rpc; this.marketMapperRevenueShareParams = this.marketMapperRevenueShareParams.bind(this); this.marketMapperRevShareDetails = this.marketMapperRevShareDetails.bind(this); + this.unconditionalRevShareConfig = this.unconditionalRevShareConfig.bind(this); } marketMapperRevenueShareParams(request: QueryMarketMapperRevenueShareParams = {}): Promise { @@ -35,6 +39,12 @@ export class QueryClientImpl implements Query { return promise.then(data => QueryMarketMapperRevShareDetailsResponse.decode(new _m0.Reader(data))); } + unconditionalRevShareConfig(request: QueryUnconditionalRevShareConfig = {}): Promise { + const data = QueryUnconditionalRevShareConfig.encode(request).finish(); + const promise = this.rpc.request("dydxprotocol.revshare.Query", "UnconditionalRevShareConfig", data); + return promise.then(data => QueryUnconditionalRevShareConfigResponse.decode(new _m0.Reader(data))); + } + } export const createRpcQueryExtension = (base: QueryClient) => { const rpc = createProtobufRpcClient(base); @@ -46,6 +56,10 @@ export const createRpcQueryExtension = (base: QueryClient) => { marketMapperRevShareDetails(request: QueryMarketMapperRevShareDetails): Promise { return queryService.marketMapperRevShareDetails(request); + }, + + unconditionalRevShareConfig(request?: QueryUnconditionalRevShareConfig): Promise { + return queryService.unconditionalRevShareConfig(request); } }; diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.ts index b7b3ef17df..e729da38cb 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/query.ts @@ -1,5 +1,5 @@ import { MarketMapperRevenueShareParams, MarketMapperRevenueShareParamsSDKType } from "./params"; -import { MarketMapperRevShareDetails, MarketMapperRevShareDetailsSDKType } from "./revshare"; +import { MarketMapperRevShareDetails, MarketMapperRevShareDetailsSDKType, UnconditionalRevShareConfig, UnconditionalRevShareConfigSDKType } from "./revshare"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; /** Queries for the default market mapper revenue share params */ @@ -40,6 +40,22 @@ export interface QueryMarketMapperRevShareDetailsResponse { export interface QueryMarketMapperRevShareDetailsResponseSDKType { details?: MarketMapperRevShareDetailsSDKType; } +/** Queries unconditional revenue share details */ + +export interface QueryUnconditionalRevShareConfig {} +/** Queries unconditional revenue share details */ + +export interface QueryUnconditionalRevShareConfigSDKType {} +/** Response type for QueryUnconditionalRevShareConfig */ + +export interface QueryUnconditionalRevShareConfigResponse { + config?: UnconditionalRevShareConfig; +} +/** Response type for QueryUnconditionalRevShareConfig */ + +export interface QueryUnconditionalRevShareConfigResponseSDKType { + config?: UnconditionalRevShareConfigSDKType; +} function createBaseQueryMarketMapperRevenueShareParams(): QueryMarketMapperRevenueShareParams { return {}; @@ -208,4 +224,83 @@ export const QueryMarketMapperRevShareDetailsResponse = { return message; } +}; + +function createBaseQueryUnconditionalRevShareConfig(): QueryUnconditionalRevShareConfig { + return {}; +} + +export const QueryUnconditionalRevShareConfig = { + encode(_: QueryUnconditionalRevShareConfig, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): QueryUnconditionalRevShareConfig { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseQueryUnconditionalRevShareConfig(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(_: DeepPartial): QueryUnconditionalRevShareConfig { + const message = createBaseQueryUnconditionalRevShareConfig(); + return message; + } + +}; + +function createBaseQueryUnconditionalRevShareConfigResponse(): QueryUnconditionalRevShareConfigResponse { + return { + config: undefined + }; +} + +export const QueryUnconditionalRevShareConfigResponse = { + encode(message: QueryUnconditionalRevShareConfigResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.config !== undefined) { + UnconditionalRevShareConfig.encode(message.config, writer.uint32(10).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): QueryUnconditionalRevShareConfigResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseQueryUnconditionalRevShareConfigResponse(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.config = UnconditionalRevShareConfig.decode(reader, reader.uint32()); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): QueryUnconditionalRevShareConfigResponse { + const message = createBaseQueryUnconditionalRevShareConfigResponse(); + message.config = object.config !== undefined && object.config !== null ? UnconditionalRevShareConfig.fromPartial(object.config) : undefined; + return message; + } + }; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/tx.rpc.msg.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/tx.rpc.msg.ts index f6e6b53b3f..e530b096bc 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/tx.rpc.msg.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/revshare/tx.rpc.msg.ts @@ -15,7 +15,7 @@ export interface Msg { */ setMarketMapperRevShareDetailsForMarket(request: MsgSetMarketMapperRevShareDetailsForMarket): Promise; - /** SetUnconditionalRevShareConfig sets the unconditional revshare config */ + /** UpdateUnconditionalRevShareConfig sets the unconditional revshare config */ updateUnconditionalRevShareConfig(request: MsgUpdateUnconditionalRevShareConfig): Promise; } diff --git a/proto/dydxprotocol/revshare/query.proto b/proto/dydxprotocol/revshare/query.proto index 51ecd4818e..48cc58ce6f 100644 --- a/proto/dydxprotocol/revshare/query.proto +++ b/proto/dydxprotocol/revshare/query.proto @@ -25,6 +25,13 @@ service Query { option (google.api.http).get = "/dydxprotocol/revshare/market_mapper_rev_share_details/{market_id}"; } + + // Queries unconditional revenue share config + rpc UnconditionalRevShareConfig(QueryUnconditionalRevShareConfig) + returns (QueryUnconditionalRevShareConfigResponse) { + option (google.api.http).get = + "/dydxprotocol/revshare/unconditional_rev_share"; + } } // Queries for the default market mapper revenue share params @@ -41,4 +48,12 @@ message QueryMarketMapperRevShareDetails { uint32 market_id = 1; } // Response type for QueryMarketMapperRevShareDetails message QueryMarketMapperRevShareDetailsResponse { MarketMapperRevShareDetails details = 1 [ (gogoproto.nullable) = false ]; -} \ No newline at end of file +} + +// Queries unconditional revenue share details +message QueryUnconditionalRevShareConfig {} + +// Response type for QueryUnconditionalRevShareConfig +message QueryUnconditionalRevShareConfigResponse { + UnconditionalRevShareConfig config = 1 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/dydxprotocol/revshare/tx.proto b/proto/dydxprotocol/revshare/tx.proto index 70ff4c4614..c5a94cb807 100644 --- a/proto/dydxprotocol/revshare/tx.proto +++ b/proto/dydxprotocol/revshare/tx.proto @@ -21,7 +21,7 @@ service Msg { rpc SetMarketMapperRevShareDetailsForMarket( MsgSetMarketMapperRevShareDetailsForMarket) returns (MsgSetMarketMapperRevShareDetailsForMarketResponse); - // SetUnconditionalRevShareConfig sets the unconditional revshare config + // UpdateUnconditionalRevShareConfig sets the unconditional revshare config rpc UpdateUnconditionalRevShareConfig(MsgUpdateUnconditionalRevShareConfig) returns (MsgUpdateUnconditionalRevShareConfigResponse); } diff --git a/protocol/x/revshare/client/cli/query.go b/protocol/x/revshare/client/cli/query.go index ee16e428e2..27414641f1 100644 --- a/protocol/x/revshare/client/cli/query.go +++ b/protocol/x/revshare/client/cli/query.go @@ -22,6 +22,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdQueryRevShareParams()) cmd.AddCommand(CmdQueryRevShareDetailsForMarket()) + cmd.AddCommand(CmdQueryUnconditionalRevShareConfig()) return cmd } diff --git a/protocol/x/revshare/client/cli/query_params.go b/protocol/x/revshare/client/cli/query_params.go index 2e89e78b1b..2f3160cc38 100644 --- a/protocol/x/revshare/client/cli/query_params.go +++ b/protocol/x/revshare/client/cli/query_params.go @@ -66,3 +66,26 @@ func CmdQueryRevShareDetailsForMarket() *cobra.Command { return cmd } + +func CmdQueryUnconditionalRevShareConfig() *cobra.Command { + cmd := &cobra.Command{ + Use: "unconditional-revshare-config", + Short: "unconditional revshare config", + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.UnconditionalRevShareConfig( + context.Background(), + &types.QueryUnconditionalRevShareConfig{}, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/protocol/x/revshare/keeper/grpc_query_unconditional_revshare.go b/protocol/x/revshare/keeper/grpc_query_unconditional_revshare.go new file mode 100644 index 0000000000..967ca96a9b --- /dev/null +++ b/protocol/x/revshare/keeper/grpc_query_unconditional_revshare.go @@ -0,0 +1,21 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" +) + +func (k Keeper) UnconditionalRevShareConfig( + ctx context.Context, + req *types.QueryUnconditionalRevShareConfig, +) (*types.QueryUnconditionalRevShareConfigResponse, error) { + config, err := k.GetUnconditionalRevShareConfigParams(sdk.UnwrapSDKContext(ctx)) + if err != nil { + return nil, err + } + return &types.QueryUnconditionalRevShareConfigResponse{ + Config: config, + }, nil +} diff --git a/protocol/x/revshare/keeper/grpc_query_unconditional_revshare_test.go b/protocol/x/revshare/keeper/grpc_query_unconditional_revshare_test.go new file mode 100644 index 0000000000..e473d1fc29 --- /dev/null +++ b/protocol/x/revshare/keeper/grpc_query_unconditional_revshare_test.go @@ -0,0 +1,58 @@ +package keeper_test + +import ( + "testing" + + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" + "github.com/stretchr/testify/require" +) + +func TestQueryUnconditionalRevShare(t *testing.T) { + testCases := map[string]struct { + config types.UnconditionalRevShareConfig + }{ + "Single recipient": { + config: types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.AliceAccAddress.String(), + SharePpm: 100_000, + }, + }, + }, + }, + "Multiple recipients": { + config: types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.AliceAccAddress.String(), + SharePpm: 50_000, + }, + { + Address: constants.BobAccAddress.String(), + SharePpm: 30_000, + }, + }, + }, + }, + "Empty config": { + config: types.UnconditionalRevShareConfig{}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).Build() + ctx := tApp.InitChain() + k := tApp.App.RevShareKeeper + + k.SetUnconditionalRevShareConfigParams(ctx, tc.config) + + resp, err := k.UnconditionalRevShareConfig(ctx, &types.QueryUnconditionalRevShareConfig{}) + require.NoError(t, err) + require.Equal(t, tc.config, resp.Config) + }) + } +} diff --git a/protocol/x/revshare/types/query.pb.go b/protocol/x/revshare/types/query.pb.go index 0e8c70fb41..c84d8ec34c 100644 --- a/protocol/x/revshare/types/query.pb.go +++ b/protocol/x/revshare/types/query.pb.go @@ -207,44 +207,134 @@ func (m *QueryMarketMapperRevShareDetailsResponse) GetDetails() MarketMapperRevS return MarketMapperRevShareDetails{} } +// Queries unconditional revenue share details +type QueryUnconditionalRevShareConfig struct { +} + +func (m *QueryUnconditionalRevShareConfig) Reset() { *m = QueryUnconditionalRevShareConfig{} } +func (m *QueryUnconditionalRevShareConfig) String() string { return proto.CompactTextString(m) } +func (*QueryUnconditionalRevShareConfig) ProtoMessage() {} +func (*QueryUnconditionalRevShareConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_13d50c6e3048e744, []int{4} +} +func (m *QueryUnconditionalRevShareConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUnconditionalRevShareConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUnconditionalRevShareConfig.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 *QueryUnconditionalRevShareConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUnconditionalRevShareConfig.Merge(m, src) +} +func (m *QueryUnconditionalRevShareConfig) XXX_Size() int { + return m.Size() +} +func (m *QueryUnconditionalRevShareConfig) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUnconditionalRevShareConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUnconditionalRevShareConfig proto.InternalMessageInfo + +// Response type for QueryUnconditionalRevShareConfig +type QueryUnconditionalRevShareConfigResponse struct { + Config UnconditionalRevShareConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` +} + +func (m *QueryUnconditionalRevShareConfigResponse) Reset() { + *m = QueryUnconditionalRevShareConfigResponse{} +} +func (m *QueryUnconditionalRevShareConfigResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUnconditionalRevShareConfigResponse) ProtoMessage() {} +func (*QueryUnconditionalRevShareConfigResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_13d50c6e3048e744, []int{5} +} +func (m *QueryUnconditionalRevShareConfigResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUnconditionalRevShareConfigResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUnconditionalRevShareConfigResponse.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 *QueryUnconditionalRevShareConfigResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUnconditionalRevShareConfigResponse.Merge(m, src) +} +func (m *QueryUnconditionalRevShareConfigResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUnconditionalRevShareConfigResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUnconditionalRevShareConfigResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUnconditionalRevShareConfigResponse proto.InternalMessageInfo + +func (m *QueryUnconditionalRevShareConfigResponse) GetConfig() UnconditionalRevShareConfig { + if m != nil { + return m.Config + } + return UnconditionalRevShareConfig{} +} + func init() { proto.RegisterType((*QueryMarketMapperRevenueShareParams)(nil), "dydxprotocol.revshare.QueryMarketMapperRevenueShareParams") proto.RegisterType((*QueryMarketMapperRevenueShareParamsResponse)(nil), "dydxprotocol.revshare.QueryMarketMapperRevenueShareParamsResponse") proto.RegisterType((*QueryMarketMapperRevShareDetails)(nil), "dydxprotocol.revshare.QueryMarketMapperRevShareDetails") proto.RegisterType((*QueryMarketMapperRevShareDetailsResponse)(nil), "dydxprotocol.revshare.QueryMarketMapperRevShareDetailsResponse") + proto.RegisterType((*QueryUnconditionalRevShareConfig)(nil), "dydxprotocol.revshare.QueryUnconditionalRevShareConfig") + proto.RegisterType((*QueryUnconditionalRevShareConfigResponse)(nil), "dydxprotocol.revshare.QueryUnconditionalRevShareConfigResponse") } func init() { proto.RegisterFile("dydxprotocol/revshare/query.proto", fileDescriptor_13d50c6e3048e744) } var fileDescriptor_13d50c6e3048e744 = []byte{ - // 420 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, 0x2f, 0x4a, 0x2d, 0x2b, 0xce, 0x48, 0x2c, - 0x4a, 0xd5, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x03, 0x8b, 0x0b, 0x89, 0x22, 0x2b, 0xd1, 0x83, - 0x29, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x0b, 0xeb, 0x83, 0x58, 0x10, 0xc5, 0x52, 0x32, - 0xe9, 0xf9, 0xf9, 0xe9, 0x39, 0xa9, 0xfa, 0x89, 0x05, 0x99, 0xfa, 0x89, 0x79, 0x79, 0xf9, 0x25, - 0x89, 0x25, 0x99, 0xf9, 0x79, 0xc5, 0x50, 0x59, 0x25, 0xec, 0xb6, 0x15, 0x24, 0x16, 0x25, 0xe6, - 0xc2, 0xd4, 0xa8, 0x60, 0x57, 0x03, 0x63, 0x40, 0x54, 0x29, 0xa9, 0x72, 0x29, 0x07, 0x82, 0xdc, - 0xe8, 0x9b, 0x58, 0x94, 0x9d, 0x5a, 0xe2, 0x9b, 0x58, 0x50, 0x90, 0x5a, 0x14, 0x94, 0x5a, 0x96, - 0x9a, 0x57, 0x9a, 0x1a, 0x0c, 0x52, 0x16, 0x00, 0x36, 0x52, 0xa9, 0x89, 0x91, 0x4b, 0x9b, 0x08, - 0x75, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0xc1, 0x5c, 0x6c, 0x10, 0xc7, 0x48, - 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x99, 0xea, 0x61, 0xf5, 0xbc, 0x1e, 0x7e, 0xe3, 0x9c, 0x58, - 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x1a, 0xa5, 0x64, 0xcf, 0xa5, 0x80, 0xcd, 0x0d, 0x60, 0x0d, - 0x2e, 0xa9, 0x25, 0x89, 0x99, 0x39, 0xc5, 0x42, 0xd2, 0x5c, 0x9c, 0xb9, 0x60, 0xe9, 0xf8, 0xcc, - 0x14, 0xb0, 0xdd, 0xbc, 0x41, 0x1c, 0x10, 0x01, 0xcf, 0x14, 0xa5, 0x3a, 0x2e, 0x0d, 0x42, 0x06, - 0xc0, 0x7d, 0x10, 0xc4, 0xc5, 0x9e, 0x02, 0x11, 0x82, 0x7a, 0xc1, 0x88, 0x38, 0x2f, 0x20, 0x1b, - 0x06, 0x75, 0x3f, 0xcc, 0x20, 0xa3, 0xf3, 0xcc, 0x5c, 0xac, 0x60, 0x07, 0x08, 0xdd, 0x67, 0xe4, - 0x92, 0xc3, 0xef, 0x77, 0x21, 0x2b, 0x1c, 0xf6, 0x11, 0x11, 0x0d, 0x52, 0x4e, 0xe4, 0xeb, 0x85, - 0x05, 0x80, 0x92, 0x6d, 0xd3, 0xe5, 0x27, 0x93, 0x99, 0xcc, 0x85, 0x4c, 0xf5, 0xb1, 0x27, 0x24, - 0x68, 0x30, 0xe7, 0x82, 0xcd, 0x89, 0x2f, 0x4a, 0x2d, 0x8b, 0x07, 0x8b, 0xc7, 0x43, 0x22, 0x4b, - 0xe8, 0x31, 0x23, 0x97, 0x34, 0xbe, 0x88, 0x32, 0x27, 0xc1, 0x89, 0xc8, 0x1a, 0xa5, 0xec, 0xc9, - 0xd4, 0x08, 0xf7, 0x98, 0x17, 0xd8, 0x63, 0x2e, 0x42, 0x4e, 0x24, 0x7a, 0x0c, 0x1a, 0x8b, 0xfa, - 0xd5, 0xf0, 0x04, 0x56, 0xeb, 0x14, 0x72, 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, 0x56, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xa8, 0xf6, 0x94, 0x99, - 0xe8, 0x26, 0x67, 0x24, 0x66, 0xe6, 0xe9, 0xc3, 0x45, 0x2a, 0x10, 0x76, 0x97, 0x54, 0x16, 0xa4, - 0x16, 0x27, 0xb1, 0x81, 0xa5, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x31, 0xa4, 0xeb, 0xf4, - 0x55, 0x04, 0x00, 0x00, + // 496 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x4f, 0x6b, 0xd4, 0x40, + 0x18, 0xc6, 0x77, 0xc4, 0xae, 0x3a, 0xe2, 0x65, 0x50, 0x90, 0x5d, 0x89, 0x75, 0x54, 0x28, 0x88, + 0x19, 0x59, 0xad, 0x85, 0x82, 0x14, 0xd6, 0x5e, 0x14, 0x0a, 0x35, 0xd5, 0x8b, 0x97, 0x65, 0x9a, + 0x8c, 0xd9, 0xc1, 0xdd, 0x99, 0x38, 0xc9, 0x86, 0x2e, 0xfe, 0x39, 0xf4, 0x13, 0x08, 0x7e, 0x02, + 0xbf, 0x4d, 0x6f, 0x16, 0xbc, 0x78, 0x52, 0xd9, 0xf8, 0x41, 0x24, 0x93, 0x49, 0x9a, 0x42, 0x3a, + 0x4d, 0x7b, 0x1b, 0xde, 0x79, 0xde, 0xe7, 0x7d, 0x7e, 0x99, 0x37, 0xf0, 0x4e, 0x30, 0x0f, 0xf6, + 0x22, 0x25, 0x13, 0xe9, 0xcb, 0x09, 0x51, 0x2c, 0x8d, 0xc7, 0x54, 0x31, 0xf2, 0x61, 0xc6, 0xd4, + 0xdc, 0xd5, 0x75, 0x74, 0xa3, 0x2e, 0x71, 0x4b, 0x49, 0xef, 0x7a, 0x28, 0x43, 0xa9, 0xcb, 0x24, + 0x3f, 0x15, 0xe2, 0xde, 0xad, 0x50, 0xca, 0x70, 0xc2, 0x08, 0x8d, 0x38, 0xa1, 0x42, 0xc8, 0x84, + 0x26, 0x5c, 0x8a, 0xd8, 0xdc, 0xe2, 0xe6, 0x69, 0x11, 0x55, 0x74, 0x5a, 0x6a, 0xee, 0x35, 0x6b, + 0xca, 0x43, 0xa1, 0xc2, 0xf7, 0xe1, 0xdd, 0x57, 0x79, 0xc6, 0x2d, 0xaa, 0xde, 0xb3, 0x64, 0x8b, + 0x46, 0x11, 0x53, 0x1e, 0x4b, 0x99, 0x98, 0xb1, 0x9d, 0x5c, 0xb6, 0xad, 0x2d, 0xf1, 0x3e, 0x80, + 0x0f, 0x5a, 0xe8, 0x3c, 0x16, 0x47, 0x52, 0xc4, 0x0c, 0xed, 0xc0, 0x6e, 0x11, 0xe6, 0x26, 0x58, + 0x06, 0x2b, 0x57, 0x07, 0xab, 0x6e, 0x23, 0xbc, 0x6b, 0xb7, 0x1b, 0x5e, 0x3c, 0xf8, 0x7d, 0xbb, + 0xe3, 0x19, 0x2b, 0xbc, 0x01, 0x97, 0x9b, 0x32, 0xe8, 0x86, 0x4d, 0x96, 0x50, 0x3e, 0x89, 0x51, + 0x1f, 0x5e, 0x99, 0xea, 0xeb, 0x11, 0x0f, 0xf4, 0xec, 0x6b, 0xde, 0xe5, 0xa2, 0xf0, 0x22, 0xc0, + 0x5f, 0xe0, 0xca, 0x69, 0x06, 0x15, 0x81, 0x07, 0x2f, 0x05, 0x45, 0xc9, 0x20, 0x0c, 0xda, 0x21, + 0xd4, 0xcd, 0x4c, 0xfe, 0xd2, 0x08, 0x63, 0x03, 0xf0, 0x46, 0xf8, 0x52, 0x04, 0x3c, 0x7f, 0x51, + 0x3a, 0x29, 0x7b, 0x9e, 0x4b, 0xf1, 0x8e, 0x87, 0xf8, 0x93, 0xc9, 0x68, 0xd1, 0x54, 0x19, 0xb7, + 0x61, 0xd7, 0xd7, 0x95, 0x53, 0x22, 0x5a, 0xbc, 0xca, 0x4f, 0x5c, 0xf8, 0x0c, 0xbe, 0x2f, 0xc1, + 0x25, 0x3d, 0x1e, 0xfd, 0x01, 0xd0, 0xb1, 0xbf, 0x0e, 0x5a, 0x3f, 0x61, 0x5c, 0x8b, 0x45, 0xe9, + 0x0d, 0xcf, 0xdf, 0x5b, 0xe2, 0xe3, 0x67, 0xfb, 0x3f, 0xff, 0x7d, 0xbb, 0xb0, 0x86, 0x56, 0x49, + 0xf3, 0xaa, 0x9b, 0x45, 0x98, 0x6a, 0x9f, 0x91, 0x62, 0xe9, 0x48, 0xd7, 0x47, 0xc5, 0x3a, 0xa1, + 0x0c, 0xc0, 0xbe, 0x6d, 0x95, 0xd6, 0xce, 0x10, 0xb1, 0xde, 0xd8, 0xdb, 0x38, 0x67, 0x63, 0x05, + 0xf6, 0x52, 0x83, 0x6d, 0xa2, 0xe1, 0x19, 0xc1, 0xcc, 0x9e, 0x91, 0x8f, 0xd5, 0x2f, 0xf0, 0x19, + 0xfd, 0x00, 0xb0, 0x6f, 0x79, 0x7f, 0x3b, 0xa5, 0xa5, 0xd1, 0x4e, 0xd9, 0x62, 0x7b, 0xf1, 0x53, + 0x4d, 0xf9, 0x08, 0xb9, 0x27, 0x50, 0xce, 0xea, 0x1e, 0x47, 0x94, 0xc3, 0xd7, 0x07, 0x0b, 0x07, + 0x1c, 0x2e, 0x1c, 0xf0, 0x77, 0xe1, 0x80, 0xaf, 0x99, 0xd3, 0x39, 0xcc, 0x9c, 0xce, 0xaf, 0xcc, + 0xe9, 0xbc, 0x5d, 0x0f, 0x79, 0x32, 0x9e, 0xed, 0xba, 0xbe, 0x9c, 0x1e, 0xf7, 0x4c, 0x9f, 0x3c, + 0xf4, 0xc7, 0x94, 0x0b, 0x52, 0x55, 0xf6, 0x8e, 0xe6, 0x24, 0xf3, 0x88, 0xc5, 0xbb, 0x5d, 0x7d, + 0xf5, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x34, 0xdf, 0xbf, 0xc9, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -264,6 +354,8 @@ type QueryClient interface { MarketMapperRevenueShareParams(ctx context.Context, in *QueryMarketMapperRevenueShareParams, opts ...grpc.CallOption) (*QueryMarketMapperRevenueShareParamsResponse, error) // Queries market mapper revenue share details for a specific market MarketMapperRevShareDetails(ctx context.Context, in *QueryMarketMapperRevShareDetails, opts ...grpc.CallOption) (*QueryMarketMapperRevShareDetailsResponse, error) + // Queries unconditional revenue share config + UnconditionalRevShareConfig(ctx context.Context, in *QueryUnconditionalRevShareConfig, opts ...grpc.CallOption) (*QueryUnconditionalRevShareConfigResponse, error) } type queryClient struct { @@ -292,6 +384,15 @@ func (c *queryClient) MarketMapperRevShareDetails(ctx context.Context, in *Query return out, nil } +func (c *queryClient) UnconditionalRevShareConfig(ctx context.Context, in *QueryUnconditionalRevShareConfig, opts ...grpc.CallOption) (*QueryUnconditionalRevShareConfigResponse, error) { + out := new(QueryUnconditionalRevShareConfigResponse) + err := c.cc.Invoke(ctx, "/dydxprotocol.revshare.Query/UnconditionalRevShareConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // MarketMapperRevenueShareParams queries the revenue share params for the @@ -299,6 +400,8 @@ type QueryServer interface { MarketMapperRevenueShareParams(context.Context, *QueryMarketMapperRevenueShareParams) (*QueryMarketMapperRevenueShareParamsResponse, error) // Queries market mapper revenue share details for a specific market MarketMapperRevShareDetails(context.Context, *QueryMarketMapperRevShareDetails) (*QueryMarketMapperRevShareDetailsResponse, error) + // Queries unconditional revenue share config + UnconditionalRevShareConfig(context.Context, *QueryUnconditionalRevShareConfig) (*QueryUnconditionalRevShareConfigResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -311,6 +414,9 @@ func (*UnimplementedQueryServer) MarketMapperRevenueShareParams(ctx context.Cont func (*UnimplementedQueryServer) MarketMapperRevShareDetails(ctx context.Context, req *QueryMarketMapperRevShareDetails) (*QueryMarketMapperRevShareDetailsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method MarketMapperRevShareDetails not implemented") } +func (*UnimplementedQueryServer) UnconditionalRevShareConfig(ctx context.Context, req *QueryUnconditionalRevShareConfig) (*QueryUnconditionalRevShareConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnconditionalRevShareConfig not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -352,6 +458,24 @@ func _Query_MarketMapperRevShareDetails_Handler(srv interface{}, ctx context.Con return interceptor(ctx, in, info, handler) } +func _Query_UnconditionalRevShareConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUnconditionalRevShareConfig) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UnconditionalRevShareConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dydxprotocol.revshare.Query/UnconditionalRevShareConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UnconditionalRevShareConfig(ctx, req.(*QueryUnconditionalRevShareConfig)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "dydxprotocol.revshare.Query", HandlerType: (*QueryServer)(nil), @@ -364,6 +488,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "MarketMapperRevShareDetails", Handler: _Query_MarketMapperRevShareDetails_Handler, }, + { + MethodName: "UnconditionalRevShareConfig", + Handler: _Query_UnconditionalRevShareConfig_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "dydxprotocol/revshare/query.proto", @@ -486,6 +614,62 @@ func (m *QueryMarketMapperRevShareDetailsResponse) MarshalToSizedBuffer(dAtA []b return len(dAtA) - i, nil } +func (m *QueryUnconditionalRevShareConfig) 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 *QueryUnconditionalRevShareConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUnconditionalRevShareConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryUnconditionalRevShareConfigResponse) 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 *QueryUnconditionalRevShareConfigResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUnconditionalRevShareConfigResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Config.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -540,6 +724,26 @@ func (m *QueryMarketMapperRevShareDetailsResponse) Size() (n int) { return n } +func (m *QueryUnconditionalRevShareConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryUnconditionalRevShareConfigResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Config.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -831,6 +1035,139 @@ func (m *QueryMarketMapperRevShareDetailsResponse) Unmarshal(dAtA []byte) error } return nil } +func (m *QueryUnconditionalRevShareConfig) 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 ErrIntOverflowQuery + } + 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: QueryUnconditionalRevShareConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUnconditionalRevShareConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUnconditionalRevShareConfigResponse) 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 ErrIntOverflowQuery + } + 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: QueryUnconditionalRevShareConfigResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUnconditionalRevShareConfigResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Config", 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 + } + if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/protocol/x/revshare/types/query.pb.gw.go b/protocol/x/revshare/types/query.pb.gw.go index 3f2c7025d1..13ce5f4ad4 100644 --- a/protocol/x/revshare/types/query.pb.gw.go +++ b/protocol/x/revshare/types/query.pb.gw.go @@ -105,6 +105,24 @@ func local_request_Query_MarketMapperRevShareDetails_0(ctx context.Context, mars } +func request_Query_UnconditionalRevShareConfig_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUnconditionalRevShareConfig + var metadata runtime.ServerMetadata + + msg, err := client.UnconditionalRevShareConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_UnconditionalRevShareConfig_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUnconditionalRevShareConfig + var metadata runtime.ServerMetadata + + msg, err := server.UnconditionalRevShareConfig(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -157,6 +175,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_UnconditionalRevShareConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_UnconditionalRevShareConfig_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UnconditionalRevShareConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -238,6 +279,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_UnconditionalRevShareConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_UnconditionalRevShareConfig_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UnconditionalRevShareConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -245,10 +306,14 @@ var ( pattern_Query_MarketMapperRevenueShareParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "revshare", "market_mapper_rev_share_params"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_MarketMapperRevShareDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"dydxprotocol", "revshare", "market_mapper_rev_share_details", "market_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_UnconditionalRevShareConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "revshare", "unconditional_rev_share"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_MarketMapperRevenueShareParams_0 = runtime.ForwardResponseMessage forward_Query_MarketMapperRevShareDetails_0 = runtime.ForwardResponseMessage + + forward_Query_UnconditionalRevShareConfig_0 = runtime.ForwardResponseMessage ) diff --git a/protocol/x/revshare/types/tx.pb.go b/protocol/x/revshare/types/tx.pb.go index 5433d75798..88e5c8a5f0 100644 --- a/protocol/x/revshare/types/tx.pb.go +++ b/protocol/x/revshare/types/tx.pb.go @@ -394,7 +394,7 @@ type MsgClient interface { // SetMarketMapperRevenueShareDetails sets the revenue share details for a // market mapper. SetMarketMapperRevShareDetailsForMarket(ctx context.Context, in *MsgSetMarketMapperRevShareDetailsForMarket, opts ...grpc.CallOption) (*MsgSetMarketMapperRevShareDetailsForMarketResponse, error) - // SetUnconditionalRevShareConfig sets the unconditional revshare config + // UpdateUnconditionalRevShareConfig sets the unconditional revshare config UpdateUnconditionalRevShareConfig(ctx context.Context, in *MsgUpdateUnconditionalRevShareConfig, opts ...grpc.CallOption) (*MsgUpdateUnconditionalRevShareConfigResponse, error) } @@ -441,7 +441,7 @@ type MsgServer interface { // SetMarketMapperRevenueShareDetails sets the revenue share details for a // market mapper. SetMarketMapperRevShareDetailsForMarket(context.Context, *MsgSetMarketMapperRevShareDetailsForMarket) (*MsgSetMarketMapperRevShareDetailsForMarketResponse, error) - // SetUnconditionalRevShareConfig sets the unconditional revshare config + // UpdateUnconditionalRevShareConfig sets the unconditional revshare config UpdateUnconditionalRevShareConfig(context.Context, *MsgUpdateUnconditionalRevShareConfig) (*MsgUpdateUnconditionalRevShareConfigResponse, error) } From d06d6cb1437640d510fa198ed03ad9d54aadc231 Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Thu, 26 Sep 2024 21:20:20 -0400 Subject: [PATCH 050/120] [OTE-840] add missing HasEndBlocker interface (#2384) --- protocol/x/affiliates/module.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/protocol/x/affiliates/module.go b/protocol/x/affiliates/module.go index 946dcd2857..db70ee60a0 100644 --- a/protocol/x/affiliates/module.go +++ b/protocol/x/affiliates/module.go @@ -1,6 +1,7 @@ package affiliates import ( + "context" "encoding/json" "fmt" @@ -25,6 +26,7 @@ var ( _ module.HasGenesisBasics = AppModuleBasic{} _ appmodule.AppModule = AppModule{} + _ appmodule.HasEndBlocker = AppModule{} _ module.HasConsensusVersion = AppModule{} _ module.HasGenesis = AppModule{} _ module.HasServices = AppModule{} @@ -143,9 +145,10 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw // be set to 1. func (AppModule) ConsensusVersion() uint64 { return 1 } -func (am AppModule) EndBlock(ctx sdk.Context) { +func (am AppModule) EndBlock(ctx context.Context) error { EndBlocker( lib.UnwrapSDKContext(ctx, types.ModuleName), &am.keeper, ) + return nil } From d702760f98cc69d991de7ca001686888fcf4413a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:43:25 -0400 Subject: [PATCH 051/120] migrate vault shares to megavault shares in v7 upgrade handler (backport #2379) (#2381) Co-authored-by: Tian --- protocol/app/upgrades/v7.0.0/upgrade.go | 71 +++++++++++ .../upgrades/v7.0.0/upgrade_container_test.go | 66 ++++++++++ .../containertest/preupgrade_genesis.json | 53 +++++++- protocol/x/vault/keeper/deprecated_state.go | 116 ++++++++++++++++++ 4 files changed, 304 insertions(+), 2 deletions(-) diff --git a/protocol/app/upgrades/v7.0.0/upgrade.go b/protocol/app/upgrades/v7.0.0/upgrade.go index 14a2b670b1..d5a0b8e970 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade.go +++ b/protocol/app/upgrades/v7.0.0/upgrade.go @@ -3,6 +3,7 @@ package v_7_0_0 import ( "context" "fmt" + "math/big" upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,6 +15,11 @@ import ( vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" ) +const ( + // Each megavault share is worth 1 USDC. + QUOTE_QUANTUMS_PER_MEGAVAULT_SHARE = 1_000_000 +) + func initCurrencyPairIDCache(ctx sdk.Context, k pricestypes.PricesKeeper) { marketParams := k.GetAllMarketParams(ctx) for _, mp := range marketParams { @@ -55,6 +61,68 @@ func migrateVaultQuotingParamsToVaultParams(ctx sdk.Context, k vaultkeeper.Keepe } } +// In 6.x, +// Total shares store (key prefix `TotalShares:`) is `vaultId -> shares` +// Owner shares store (key prefix `OwnerShares:`) is `vaultId -> owner -> shares` +// In 7.x, +// Total shares store is just `"TotalShares" -> shares` +// Owner shares store (key prefix `OwnerShares:`) is `owner -> shares` +// Thus, this function +// 1. Calculate how much equity each owner owns +// 2. Delete all keys in deprecated total shares and owner shares stores +// 3. Grant each owner 1 megavault share per usdc of equity owned +// 4. Set total megavault shares to sum of all owner shares granted +func migrateVaultSharesToMegavaultShares(ctx sdk.Context, k vaultkeeper.Keeper) { + ctx.Logger().Info("Migrating vault shares to megavault shares") + quoteQuantumsPerShare := big.NewInt(QUOTE_QUANTUMS_PER_MEGAVAULT_SHARE) + + ownerEquities := k.UnsafeGetAllOwnerEquities(ctx) + ctx.Logger().Info(fmt.Sprintf("Calculated owner equities %s", ownerEquities)) + k.UnsafeDeleteAllVaultTotalShares(ctx) + ctx.Logger().Info("Deleted all keys in deprecated vault total shares store") + k.UnsafeDeleteAllVaultOwnerShares(ctx) + ctx.Logger().Info("Deleted all keys in deprecated vault owner shares store") + + totalShares := big.NewInt(0) + for owner, equity := range ownerEquities { + ownerShares := new(big.Int).Quo( + equity.Num(), + equity.Denom(), + ) + ownerShares.Quo(ownerShares, quoteQuantumsPerShare) + + if ownerShares.Sign() <= 0 { + ctx.Logger().Warn(fmt.Sprintf( + "Owner %s has non-positive shares %s from %s quote quantums", + owner, + ownerShares, + equity, + )) + continue + } + + err := k.SetOwnerShares(ctx, owner, vaulttypes.BigIntToNumShares(ownerShares)) + if err != nil { + panic(err) + } + ctx.Logger().Info(fmt.Sprintf( + "Set megavault owner shares of %s: shares=%s, equity=%s", + owner, + ownerShares, + equity, + )) + + totalShares.Add(totalShares, ownerShares) + } + + err := k.SetTotalShares(ctx, vaulttypes.BigIntToNumShares(totalShares)) + if err != nil { + panic(err) + } + ctx.Logger().Info(fmt.Sprintf("Set megavault total shares to: %s", totalShares)) + ctx.Logger().Info("Successfully migrated vault shares to megavault shares") +} + func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, @@ -71,6 +139,9 @@ func CreateUpgradeHandler( // Migrate vault quoting params to vault params. migrateVaultQuotingParamsToVaultParams(sdkCtx, vaultKeeper) + // Migrate vault shares to megavault shares. + migrateVaultSharesToMegavaultShares(sdkCtx, vaultKeeper) + return mm.RunMigrations(ctx, configurator, vm) } } diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go index e0df3171d7..ccc0c79883 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go @@ -3,6 +3,7 @@ package v_7_0_0_test import ( + "math/big" "testing" "github.com/cosmos/gogoproto/proto" @@ -49,6 +50,7 @@ func preUpgradeChecks(node *containertest.Node, t *testing.T) { func postUpgradeChecks(node *containertest.Node, t *testing.T) { // Add test for your upgrade handler logic below postUpgradeVaultParamsCheck(node, t) + postUpgradeMegavaultSharesCheck(node, t) // Check that the affiliates module has been initialized with the default tiers. postUpgradeAffiliatesModuleTiersCheck(node, t) @@ -101,6 +103,70 @@ func checkVaultParams( require.Equal(t, expectedQuotingParams, vaultParamsResp.VaultParams.QuotingParams) } +func postUpgradeMegavaultSharesCheck(node *containertest.Node, t *testing.T) { + // Alice equity = vault_0_equity * 1 + vault_1_equity * 1/3 + vault_2_equity * 123_456/556_677 + // = 1_000 + 2_000 * 1/3 + 3_000 * 123_456/556_677 + // ~= 2331.99 + // Bob equity = vault_1_equity * 1/3 + vault_2_equity * 433_221/556_677 + // = 2_000 * 1/3 + 3_000 * 433_221/556_677 + // ~= 3001.35 + // Carl equity = vault_1_equity * 1/3 + // = 2_000 * 1/3 + // ~= 666.67 + // 1 USDC in equity should be granted 1 megavault share and round down to nearest integer. + expectedOwnerShares := map[string]*big.Int{ + constants.AliceAccAddress.String(): big.NewInt(2_331), + constants.BobAccAddress.String(): big.NewInt(3_001), + constants.CarlAccAddress.String(): big.NewInt(666), + } + // 2331 + 3001 + 666 = 5998 + expectedTotalShares := big.NewInt(5_998) + + // Check MegaVault total shares. + resp, err := containertest.Query( + node, + vaulttypes.NewQueryClient, + vaulttypes.QueryClient.MegavaultTotalShares, + &vaulttypes.QueryMegavaultTotalSharesRequest{}, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + totalSharesResp := vaulttypes.QueryMegavaultTotalSharesResponse{} + err = proto.UnmarshalText(resp.String(), &totalSharesResp) + require.NoError(t, err) + + require.Equal( + t, + expectedTotalShares, + totalSharesResp.TotalShares.NumShares.BigInt(), + ) + + // Check MegaVault owner shares. + resp, err = containertest.Query( + node, + vaulttypes.NewQueryClient, + vaulttypes.QueryClient.MegavaultAllOwnerShares, + &vaulttypes.QueryMegavaultAllOwnerSharesRequest{}, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + allOwnerSharesResp := vaulttypes.QueryMegavaultAllOwnerSharesResponse{} + err = proto.UnmarshalText(resp.String(), &allOwnerSharesResp) + require.NoError(t, err) + + require.Len(t, allOwnerSharesResp.OwnerShares, 3) + gotOwnerShares := make(map[string]*big.Int) + for _, ownerShare := range allOwnerSharesResp.OwnerShares { + gotOwnerShares[ownerShare.Owner] = ownerShare.Shares.NumShares.BigInt() + } + for owner, expectedShares := range expectedOwnerShares { + require.Contains(t, gotOwnerShares, owner) + require.Equal(t, expectedShares, gotOwnerShares[owner]) + } +} + func postUpgradeAffiliatesModuleTiersCheck(node *containertest.Node, t *testing.T) { resp, err := containertest.Query( node, diff --git a/protocol/testing/containertest/preupgrade_genesis.json b/protocol/testing/containertest/preupgrade_genesis.json index b75b997ead..678634c694 100644 --- a/protocol/testing/containertest/preupgrade_genesis.json +++ b/protocol/testing/containertest/preupgrade_genesis.json @@ -4354,7 +4354,21 @@ "asset_positions": [ { "asset_id": 0, - "quantums": "1000000000", + "quantums": "2000000000", + "index": 0 + } + ] + }, + { + "id": { + "owner": "dydx190te44zcctdgk0qmqtenve2m00g3r2dn7ntd72", + "number": 0 + }, + "margin_enabled": true, + "asset_positions": [ + { + "asset_id": 0, + "quantums": "3000000000", "index": 0 } ] @@ -4405,7 +4419,7 @@ "number": 1 }, "total_shares": { - "num_shares": "1000000000" + "num_shares": "3000000000" }, "owner_shares": [ { @@ -4413,6 +4427,41 @@ "shares": { "num_shares": "1000000000" } + }, + { + "owner": "dydx10fx7sy6ywd5senxae9dwytf8jxek3t2gcen2vs", + "shares": { + "num_shares": "1000000000" + } + }, + { + "owner": "dydx1fjg6zp6vv8t9wvy4lps03r5l4g7tkjw9wvmh70", + "shares": { + "num_shares": "1000000000" + } + } + ] + }, + { + "vault_id": { + "type": "VAULT_TYPE_CLOB", + "number": 2 + }, + "total_shares": { + "num_shares": "556677" + }, + "owner_shares": [ + { + "owner": "dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4", + "shares": { + "num_shares": "123456" + } + }, + { + "owner": "dydx10fx7sy6ywd5senxae9dwytf8jxek3t2gcen2vs", + "shares": { + "num_shares": "433221" + } } ] } diff --git a/protocol/x/vault/keeper/deprecated_state.go b/protocol/x/vault/keeper/deprecated_state.go index d4b05ec88f..14fcdabf62 100644 --- a/protocol/x/vault/keeper/deprecated_state.go +++ b/protocol/x/vault/keeper/deprecated_state.go @@ -1,6 +1,8 @@ package keeper import ( + "math/big" + "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,6 +22,11 @@ const ( // Deprecated: For use by the v7.x upgrade handler // TotalSharesKeyPrefix is the prefix to retrieve all TotalShares. TotalSharesKeyPrefix = "TotalShares:" + + // Deprecated: For use by the v7.x upgrade handler + // OwnerSharesKeyPrefix is the prefix to retrieve all OwnerShares. + // OwnerShares store: vaultId VaultId -> owner string -> shares NumShares. + OwnerSharesKeyPrefix = "OwnerShares:" ) // v5.x state, used for v6.x upgrade. @@ -116,3 +123,112 @@ func (k Keeper) UnsafeGetAllVaultIds(ctx sdk.Context) []types.VaultId { } return vaultIds } + +// GetTotalShares gets TotalShares for a vault. +// Deprecated and used for v7.x upgrade handler +func (k Keeper) UnsafeGetTotalShares( + ctx sdk.Context, + vaultId types.VaultId, +) (val types.NumShares, exists bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(TotalSharesKeyPrefix)) + + b := store.Get(vaultId.ToStateKey()) + if b == nil { + return val, false + } + + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +// UnsafeGetAllOwnerShares gets all owner shares of a given vault. +// Deprecated and used for v7.x upgrade handler +func (k Keeper) UnsafeGetAllOwnerShares( + ctx sdk.Context, + vaultId types.VaultId, +) []*types.OwnerShare { + allOwnerShares := []*types.OwnerShare{} + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.OwnerSharesKeyPrefix)) + ownerSharesStore := prefix.NewStore(store, vaultId.ToStateKeyPrefix()) + ownerSharesIterator := storetypes.KVStorePrefixIterator(ownerSharesStore, []byte{}) + defer ownerSharesIterator.Close() + for ; ownerSharesIterator.Valid(); ownerSharesIterator.Next() { + owner := string(ownerSharesIterator.Key()) + var ownerShares types.NumShares + k.cdc.MustUnmarshal(ownerSharesIterator.Value(), &ownerShares) + allOwnerShares = append(allOwnerShares, &types.OwnerShare{ + Owner: owner, + Shares: ownerShares, + }) + } + return allOwnerShares +} + +// UnsafeGetAllOwnerEquities returns equity that belongs to each owner across all vaults +// using the deprecated owner shares and total shares state. +// Deprecated and used for v7.x upgrade handler +func (k Keeper) UnsafeGetAllOwnerEquities(ctx sdk.Context) map[string]*big.Rat { + ownerEquities := make(map[string]*big.Rat) + totalSharesStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(TotalSharesKeyPrefix)) + totalSharesIterator := storetypes.KVStorePrefixIterator(totalSharesStore, []byte{}) + defer totalSharesIterator.Close() + for ; totalSharesIterator.Valid(); totalSharesIterator.Next() { + vaultId, err := types.GetVaultIdFromStateKey(totalSharesIterator.Key()) + if err != nil { + panic(err) + } + + var vaultTotalShares types.NumShares + k.cdc.MustUnmarshal(totalSharesIterator.Value(), &vaultTotalShares) + bigVaultTotalShares := vaultTotalShares.NumShares.BigInt() + vaultEquity, err := k.GetVaultEquity(ctx, *vaultId) + if err != nil { + panic(err) + } + + ownerShares := k.UnsafeGetAllOwnerShares(ctx, *vaultId) + for _, ownerShare := range ownerShares { + // owner equity in this vault = vault equity * owner shares / vault total shares + ownerEquity := new(big.Rat).SetInt(vaultEquity) + ownerEquity.Mul( + ownerEquity, + new(big.Rat).SetInt(ownerShare.Shares.NumShares.BigInt()), + ) + ownerEquity.Quo( + ownerEquity, + new(big.Rat).SetInt(bigVaultTotalShares), + ) + + if e, ok := ownerEquities[ownerShare.Owner]; ok { + ownerEquities[ownerShare.Owner] = e.Add(e, ownerEquity) + } else { + ownerEquities[ownerShare.Owner] = ownerEquity + } + } + } + + return ownerEquities +} + +// UnsafeDeleteVaultTotalShares deletes total shares of a given vault from state. +// Used for v7.x upgrade handler +func (k Keeper) UnsafeDeleteAllVaultTotalShares(ctx sdk.Context) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(TotalSharesKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} + +// UnsafeDeleteVaultOwnerShares deletes all owner shares of a given vault from state. +// Used for v7.x upgrade handler +func (k Keeper) UnsafeDeleteAllVaultOwnerShares(ctx sdk.Context) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(OwnerSharesKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} From 68c70d1c5cb0d3058637e6c66014d6f1a4ea837a Mon Sep 17 00:00:00 2001 From: Tian Date: Fri, 27 Sep 2024 14:58:06 -0400 Subject: [PATCH 052/120] register deprecated MsgSetVaultQuotingParams (#2392) --- .../src/codegen/dydxprotocol/vault/tx.ts | 259 ++++-- proto/dydxprotocol/vault/tx.proto | 39 +- protocol/app/msgs/all_msgs.go | 3 +- protocol/app/msgs/unsupported_msgs.go | 3 + protocol/app/msgs/unsupported_msgs_test.go | 1 + protocol/lib/ante/nested_msg_test.go | 2 + protocol/lib/ante/unsupported_msgs.go | 2 + protocol/x/vault/types/codec.go | 6 + protocol/x/vault/types/tx.pb.go | 816 ++++++++++++------ 9 files changed, 771 insertions(+), 360 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts index d26fa588ef..3a8212755b 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts @@ -184,32 +184,6 @@ export interface MsgUnlockSharesResponseSDKType { /** The number of shares unlocked. */ unlocked_shares?: NumSharesSDKType; } -/** - * MsgUpdateParams is the Msg/UpdateParams request type. - * Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. - */ - -/** @deprecated */ - -export interface MsgUpdateParams { - authority: string; - /** The parameters to update. Each field must be set. */ - - params?: Params; -} -/** - * MsgUpdateParams is the Msg/UpdateParams request type. - * Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. - */ - -/** @deprecated */ - -export interface MsgUpdateParamsSDKType { - authority: string; - /** The parameters to update. Each field must be set. */ - - params?: ParamsSDKType; -} /** MsgUpdateOperatorParams is the Msg/UpdateOperatorParams request type. */ export interface MsgUpdateOperatorParams { @@ -288,6 +262,64 @@ export interface MsgRetrieveFromVaultResponse {} /** MsgRetrieveFromVaultResponse is the Msg/RetrieveFromVault response type. */ export interface MsgRetrieveFromVaultResponseSDKType {} +/** + * MsgUpdateParams is the Msg/UpdateParams request type. + * Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. + */ + +/** @deprecated */ + +export interface MsgUpdateParams { + authority: string; + /** The parameters to update. Each field must be set. */ + + params?: Params; +} +/** + * MsgUpdateParams is the Msg/UpdateParams request type. + * Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. + */ + +/** @deprecated */ + +export interface MsgUpdateParamsSDKType { + authority: string; + /** The parameters to update. Each field must be set. */ + + params?: ParamsSDKType; +} +/** + * MsgSetVaultQuotingParams is the Msg/SetVaultQuotingParams request type. + * Deprecated since v6.x as is replaced by MsgSetVaultParams. + */ + +/** @deprecated */ + +export interface MsgSetVaultQuotingParams { + authority: string; + /** The vault to set quoting params of. */ + + vaultId?: VaultId; + /** The quoting parameters to set. Each field must be set. */ + + quotingParams?: QuotingParams; +} +/** + * MsgSetVaultQuotingParams is the Msg/SetVaultQuotingParams request type. + * Deprecated since v6.x as is replaced by MsgSetVaultParams. + */ + +/** @deprecated */ + +export interface MsgSetVaultQuotingParamsSDKType { + authority: string; + /** The vault to set quoting params of. */ + + vault_id?: VaultIdSDKType; + /** The quoting parameters to set. Each field must be set. */ + + quoting_params?: QuotingParamsSDKType; +} function createBaseMsgDepositToMegavault(): MsgDepositToMegavault { return { @@ -787,61 +819,6 @@ export const MsgUnlockSharesResponse = { }; -function createBaseMsgUpdateParams(): MsgUpdateParams { - return { - authority: "", - params: undefined - }; -} - -export const MsgUpdateParams = { - encode(message: MsgUpdateParams, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.authority !== "") { - writer.uint32(10).string(message.authority); - } - - if (message.params !== undefined) { - Params.encode(message.params, writer.uint32(18).fork()).ldelim(); - } - - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): MsgUpdateParams { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseMsgUpdateParams(); - - while (reader.pos < end) { - const tag = reader.uint32(); - - switch (tag >>> 3) { - case 1: - message.authority = reader.string(); - break; - - case 2: - message.params = Params.decode(reader, reader.uint32()); - break; - - default: - reader.skipType(tag & 7); - break; - } - } - - return message; - }, - - fromPartial(object: DeepPartial): MsgUpdateParams { - const message = createBaseMsgUpdateParams(); - message.authority = object.authority ?? ""; - message.params = object.params !== undefined && object.params !== null ? Params.fromPartial(object.params) : undefined; - return message; - } - -}; - function createBaseMsgUpdateOperatorParams(): MsgUpdateOperatorParams { return { authority: "", @@ -1127,4 +1104,124 @@ export const MsgRetrieveFromVaultResponse = { return message; } +}; + +function createBaseMsgUpdateParams(): MsgUpdateParams { + return { + authority: "", + params: undefined + }; +} + +export const MsgUpdateParams = { + encode(message: MsgUpdateParams, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authority !== "") { + writer.uint32(10).string(message.authority); + } + + if (message.params !== undefined) { + Params.encode(message.params, writer.uint32(18).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgUpdateParams { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgUpdateParams(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.authority = reader.string(); + break; + + case 2: + message.params = Params.decode(reader, reader.uint32()); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): MsgUpdateParams { + const message = createBaseMsgUpdateParams(); + message.authority = object.authority ?? ""; + message.params = object.params !== undefined && object.params !== null ? Params.fromPartial(object.params) : undefined; + return message; + } + +}; + +function createBaseMsgSetVaultQuotingParams(): MsgSetVaultQuotingParams { + return { + authority: "", + vaultId: undefined, + quotingParams: undefined + }; +} + +export const MsgSetVaultQuotingParams = { + encode(message: MsgSetVaultQuotingParams, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authority !== "") { + writer.uint32(10).string(message.authority); + } + + if (message.vaultId !== undefined) { + VaultId.encode(message.vaultId, writer.uint32(18).fork()).ldelim(); + } + + if (message.quotingParams !== undefined) { + QuotingParams.encode(message.quotingParams, writer.uint32(26).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgSetVaultQuotingParams { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgSetVaultQuotingParams(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.authority = reader.string(); + break; + + case 2: + message.vaultId = VaultId.decode(reader, reader.uint32()); + break; + + case 3: + message.quotingParams = QuotingParams.decode(reader, reader.uint32()); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): MsgSetVaultQuotingParams { + const message = createBaseMsgSetVaultQuotingParams(); + message.authority = object.authority ?? ""; + message.vaultId = object.vaultId !== undefined && object.vaultId !== null ? VaultId.fromPartial(object.vaultId) : undefined; + message.quotingParams = object.quotingParams !== undefined && object.quotingParams !== null ? QuotingParams.fromPartial(object.quotingParams) : undefined; + return message; + } + }; \ No newline at end of file diff --git a/proto/dydxprotocol/vault/tx.proto b/proto/dydxprotocol/vault/tx.proto index 2441571500..5b786747cb 100644 --- a/proto/dydxprotocol/vault/tx.proto +++ b/proto/dydxprotocol/vault/tx.proto @@ -150,18 +150,6 @@ message MsgUnlockSharesResponse { NumShares unlocked_shares = 1 [ (gogoproto.nullable) = false ]; } -// MsgUpdateParams is the Msg/UpdateParams request type. -// Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. -message MsgUpdateParams { - option deprecated = true; - // Authority is the address that controls the module. - option (cosmos.msg.v1.signer) = "authority"; - string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; - - // The parameters to update. Each field must be set. - Params params = 2 [ (gogoproto.nullable) = false ]; -} - // MsgUpdateOperatorParams is the Msg/UpdateOperatorParams request type. message MsgUpdateOperatorParams { // Authority is the address that controls the module. @@ -214,3 +202,30 @@ message MsgRetrieveFromVault { // MsgRetrieveFromVaultResponse is the Msg/RetrieveFromVault response type. message MsgRetrieveFromVaultResponse {} + +// MsgUpdateParams is the Msg/UpdateParams request type. +// Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. +message MsgUpdateParams { + option deprecated = true; + // Authority is the address that controls the module. + option (cosmos.msg.v1.signer) = "authority"; + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // The parameters to update. Each field must be set. + Params params = 2 [ (gogoproto.nullable) = false ]; +} + +// MsgSetVaultQuotingParams is the Msg/SetVaultQuotingParams request type. +// Deprecated since v6.x as is replaced by MsgSetVaultParams. +message MsgSetVaultQuotingParams { + option deprecated = true; + // Authority is the address that controls the module. + option (cosmos.msg.v1.signer) = "authority"; + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // The vault to set quoting params of. + VaultId vault_id = 2 [ (gogoproto.nullable) = false ]; + + // The quoting parameters to set. Each field must be set. + QuotingParams quoting_params = 3 [ (gogoproto.nullable) = false ]; +} diff --git a/protocol/app/msgs/all_msgs.go b/protocol/app/msgs/all_msgs.go index 8d1bc2e519..1276ccb7cc 100644 --- a/protocol/app/msgs/all_msgs.go +++ b/protocol/app/msgs/all_msgs.go @@ -258,13 +258,14 @@ var ( "/dydxprotocol.vault.MsgRetrieveFromVaultResponse": {}, "/dydxprotocol.vault.MsgSetVaultParams": {}, "/dydxprotocol.vault.MsgSetVaultParamsResponse": {}, + "/dydxprotocol.vault.MsgSetVaultQuotingParams": {}, // deprecated "/dydxprotocol.vault.MsgUnlockShares": {}, "/dydxprotocol.vault.MsgUnlockSharesResponse": {}, "/dydxprotocol.vault.MsgUpdateDefaultQuotingParams": {}, "/dydxprotocol.vault.MsgUpdateDefaultQuotingParamsResponse": {}, "/dydxprotocol.vault.MsgUpdateOperatorParams": {}, "/dydxprotocol.vault.MsgUpdateOperatorParamsResponse": {}, - "/dydxprotocol.vault.MsgUpdateParams": {}, + "/dydxprotocol.vault.MsgUpdateParams": {}, // deprecated "/dydxprotocol.vault.MsgWithdrawFromMegavault": {}, "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse": {}, diff --git a/protocol/app/msgs/unsupported_msgs.go b/protocol/app/msgs/unsupported_msgs.go index 8770863b92..885917819c 100644 --- a/protocol/app/msgs/unsupported_msgs.go +++ b/protocol/app/msgs/unsupported_msgs.go @@ -31,6 +31,9 @@ var ( "/ibc.applications.interchain_accounts.controller.v1.MsgUpdateParamsResponse": nil, // vault + // MsgSetVaultQuotingParams is deprecated since v6.x and replaced by MsgSetVaultParams. + // nolint:staticcheck + "/dydxprotocol.vault.MsgSetVaultQuotingParams": &vaulttypes.MsgSetVaultQuotingParams{}, // MsgUpdateParams is deprecated since v6.x and replaced by MsgUpdateDefaultQuotingParams. // nolint:staticcheck "/dydxprotocol.vault.MsgUpdateParams": &vaulttypes.MsgUpdateParams{}, diff --git a/protocol/app/msgs/unsupported_msgs_test.go b/protocol/app/msgs/unsupported_msgs_test.go index b483990c82..3ba4e9041f 100644 --- a/protocol/app/msgs/unsupported_msgs_test.go +++ b/protocol/app/msgs/unsupported_msgs_test.go @@ -16,6 +16,7 @@ func TestUnsupportedMsgSamples_Key(t *testing.T) { "/cosmos.gov.v1beta1.MsgSubmitProposal", "/cosmos.gov.v1beta1.MsgSubmitProposalResponse", + "/dydxprotocol.vault.MsgSetVaultQuotingParams", "/dydxprotocol.vault.MsgUpdateParams", // ICA Controller messages diff --git a/protocol/lib/ante/nested_msg_test.go b/protocol/lib/ante/nested_msg_test.go index 7ce342dee0..94ffe95c58 100644 --- a/protocol/lib/ante/nested_msg_test.go +++ b/protocol/lib/ante/nested_msg_test.go @@ -72,6 +72,8 @@ func TestIsDydxMsg_Invalid(t *testing.T) { appmsgs.NormalMsgsDydxCustom, appmsgs.InternalMsgSamplesDydxCustom, map[string]sdk.Msg{ + // nolint:staticcheck + "/dydxprotocol.vault.MsgSetVaultQuotingParams": &vaulttypes.MsgSetVaultQuotingParams{}, // nolint:staticcheck "/dydxprotocol.vault.MsgUpdateParams": &vaulttypes.MsgUpdateParams{}, }, diff --git a/protocol/lib/ante/unsupported_msgs.go b/protocol/lib/ante/unsupported_msgs.go index 9ce53fd8aa..8dd69cdf6d 100644 --- a/protocol/lib/ante/unsupported_msgs.go +++ b/protocol/lib/ante/unsupported_msgs.go @@ -23,6 +23,8 @@ func IsUnsupportedMsg(msg sdk.Msg) bool { // ------- dYdX custom modules // vault // nolint:staticcheck + *vaulttypes.MsgSetVaultQuotingParams, + // nolint:staticcheck *vaulttypes.MsgUpdateParams: return true } diff --git a/protocol/x/vault/types/codec.go b/protocol/x/vault/types/codec.go index f9c7b0af3c..3173156081 100644 --- a/protocol/x/vault/types/codec.go +++ b/protocol/x/vault/types/codec.go @@ -19,6 +19,12 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgUpdateParams{}, ) + // Register deprecated MsgSetVaultQuotingParams as it's not part of msg service. + registry.RegisterInterface( + "/"+proto.MessageName(&MsgSetVaultQuotingParams{}), + (*sdk.Msg)(nil), + &MsgSetVaultQuotingParams{}, + ) } var ( diff --git a/protocol/x/vault/types/tx.pb.go b/protocol/x/vault/types/tx.pb.go index 771491a1a9..1474addf91 100644 --- a/protocol/x/vault/types/tx.pb.go +++ b/protocol/x/vault/types/tx.pb.go @@ -519,63 +519,6 @@ func (m *MsgUnlockSharesResponse) GetUnlockedShares() NumShares { return NumShares{} } -// MsgUpdateParams is the Msg/UpdateParams request type. -// Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. -// -// Deprecated: Do not use. -type MsgUpdateParams struct { - Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // The parameters to update. Each field must be set. - Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` -} - -func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } -func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateParams) ProtoMessage() {} -func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{10} -} -func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateParams.Merge(m, src) -} -func (m *MsgUpdateParams) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateParams) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo - -func (m *MsgUpdateParams) GetAuthority() string { - if m != nil { - return m.Authority - } - return "" -} - -func (m *MsgUpdateParams) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - // MsgUpdateOperatorParams is the Msg/UpdateOperatorParams request type. type MsgUpdateOperatorParams struct { Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` @@ -587,7 +530,7 @@ func (m *MsgUpdateOperatorParams) Reset() { *m = MsgUpdateOperatorParams func (m *MsgUpdateOperatorParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateOperatorParams) ProtoMessage() {} func (*MsgUpdateOperatorParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{11} + return fileDescriptor_ced574c6017ce006, []int{10} } func (m *MsgUpdateOperatorParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -638,7 +581,7 @@ func (m *MsgUpdateOperatorParamsResponse) Reset() { *m = MsgUpdateOperat func (m *MsgUpdateOperatorParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateOperatorParamsResponse) ProtoMessage() {} func (*MsgUpdateOperatorParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{12} + return fileDescriptor_ced574c6017ce006, []int{11} } func (m *MsgUpdateOperatorParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -680,7 +623,7 @@ func (m *MsgAllocateToVault) Reset() { *m = MsgAllocateToVault{} } func (m *MsgAllocateToVault) String() string { return proto.CompactTextString(m) } func (*MsgAllocateToVault) ProtoMessage() {} func (*MsgAllocateToVault) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{13} + return fileDescriptor_ced574c6017ce006, []int{12} } func (m *MsgAllocateToVault) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -731,7 +674,7 @@ func (m *MsgAllocateToVaultResponse) Reset() { *m = MsgAllocateToVaultRe func (m *MsgAllocateToVaultResponse) String() string { return proto.CompactTextString(m) } func (*MsgAllocateToVaultResponse) ProtoMessage() {} func (*MsgAllocateToVaultResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{14} + return fileDescriptor_ced574c6017ce006, []int{13} } func (m *MsgAllocateToVaultResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -773,7 +716,7 @@ func (m *MsgRetrieveFromVault) Reset() { *m = MsgRetrieveFromVault{} } func (m *MsgRetrieveFromVault) String() string { return proto.CompactTextString(m) } func (*MsgRetrieveFromVault) ProtoMessage() {} func (*MsgRetrieveFromVault) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{15} + return fileDescriptor_ced574c6017ce006, []int{14} } func (m *MsgRetrieveFromVault) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -824,7 +767,7 @@ func (m *MsgRetrieveFromVaultResponse) Reset() { *m = MsgRetrieveFromVau func (m *MsgRetrieveFromVaultResponse) String() string { return proto.CompactTextString(m) } func (*MsgRetrieveFromVaultResponse) ProtoMessage() {} func (*MsgRetrieveFromVaultResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{16} + return fileDescriptor_ced574c6017ce006, []int{15} } func (m *MsgRetrieveFromVaultResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -853,6 +796,129 @@ func (m *MsgRetrieveFromVaultResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRetrieveFromVaultResponse proto.InternalMessageInfo +// MsgUpdateParams is the Msg/UpdateParams request type. +// Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. +// +// Deprecated: Do not use. +type MsgUpdateParams struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // The parameters to update. Each field must be set. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_ced574c6017ce006, []int{16} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgSetVaultQuotingParams is the Msg/SetVaultQuotingParams request type. +// Deprecated since v6.x as is replaced by MsgSetVaultParams. +// +// Deprecated: Do not use. +type MsgSetVaultQuotingParams struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // The vault to set quoting params of. + VaultId VaultId `protobuf:"bytes,2,opt,name=vault_id,json=vaultId,proto3" json:"vault_id"` + // The quoting parameters to set. Each field must be set. + QuotingParams QuotingParams `protobuf:"bytes,3,opt,name=quoting_params,json=quotingParams,proto3" json:"quoting_params"` +} + +func (m *MsgSetVaultQuotingParams) Reset() { *m = MsgSetVaultQuotingParams{} } +func (m *MsgSetVaultQuotingParams) String() string { return proto.CompactTextString(m) } +func (*MsgSetVaultQuotingParams) ProtoMessage() {} +func (*MsgSetVaultQuotingParams) Descriptor() ([]byte, []int) { + return fileDescriptor_ced574c6017ce006, []int{17} +} +func (m *MsgSetVaultQuotingParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetVaultQuotingParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetVaultQuotingParams.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 *MsgSetVaultQuotingParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetVaultQuotingParams.Merge(m, src) +} +func (m *MsgSetVaultQuotingParams) XXX_Size() int { + return m.Size() +} +func (m *MsgSetVaultQuotingParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetVaultQuotingParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetVaultQuotingParams proto.InternalMessageInfo + +func (m *MsgSetVaultQuotingParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgSetVaultQuotingParams) GetVaultId() VaultId { + if m != nil { + return m.VaultId + } + return VaultId{} +} + +func (m *MsgSetVaultQuotingParams) GetQuotingParams() QuotingParams { + if m != nil { + return m.QuotingParams + } + return QuotingParams{} +} + func init() { proto.RegisterType((*MsgDepositToMegavault)(nil), "dydxprotocol.vault.MsgDepositToMegavault") proto.RegisterType((*MsgDepositToMegavaultResponse)(nil), "dydxprotocol.vault.MsgDepositToMegavaultResponse") @@ -864,80 +930,83 @@ func init() { proto.RegisterType((*MsgSetVaultParamsResponse)(nil), "dydxprotocol.vault.MsgSetVaultParamsResponse") proto.RegisterType((*MsgUnlockShares)(nil), "dydxprotocol.vault.MsgUnlockShares") proto.RegisterType((*MsgUnlockSharesResponse)(nil), "dydxprotocol.vault.MsgUnlockSharesResponse") - proto.RegisterType((*MsgUpdateParams)(nil), "dydxprotocol.vault.MsgUpdateParams") proto.RegisterType((*MsgUpdateOperatorParams)(nil), "dydxprotocol.vault.MsgUpdateOperatorParams") proto.RegisterType((*MsgUpdateOperatorParamsResponse)(nil), "dydxprotocol.vault.MsgUpdateOperatorParamsResponse") proto.RegisterType((*MsgAllocateToVault)(nil), "dydxprotocol.vault.MsgAllocateToVault") proto.RegisterType((*MsgAllocateToVaultResponse)(nil), "dydxprotocol.vault.MsgAllocateToVaultResponse") proto.RegisterType((*MsgRetrieveFromVault)(nil), "dydxprotocol.vault.MsgRetrieveFromVault") proto.RegisterType((*MsgRetrieveFromVaultResponse)(nil), "dydxprotocol.vault.MsgRetrieveFromVaultResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "dydxprotocol.vault.MsgUpdateParams") + proto.RegisterType((*MsgSetVaultQuotingParams)(nil), "dydxprotocol.vault.MsgSetVaultQuotingParams") } func init() { proto.RegisterFile("dydxprotocol/vault/tx.proto", fileDescriptor_ced574c6017ce006) } var fileDescriptor_ced574c6017ce006 = []byte{ - // 971 bytes of a gzipped FileDescriptorProto + // 1001 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0x3a, 0x28, 0x25, 0xaf, 0x4e, 0xd2, 0xae, 0x5c, 0xea, 0x6e, 0xda, 0x75, 0xba, 0x55, - 0x4b, 0x4a, 0xc9, 0x9a, 0xfe, 0x11, 0x7f, 0x02, 0x87, 0x36, 0xaa, 0x50, 0x2a, 0x30, 0x10, 0xbb, - 0x80, 0x84, 0x84, 0xcc, 0x64, 0x77, 0xba, 0x1e, 0xe1, 0xdd, 0x71, 0x77, 0x66, 0xdd, 0x04, 0x24, - 0x0e, 0x1c, 0x41, 0x48, 0x48, 0x88, 0x4f, 0xd0, 0x2f, 0xc0, 0x01, 0xf1, 0x11, 0x50, 0x8f, 0x15, - 0x27, 0xc4, 0xa1, 0x42, 0xf1, 0x01, 0xf1, 0x2d, 0xd0, 0xce, 0xac, 0xd7, 0xde, 0x7f, 0xc6, 0xa9, - 0x89, 0x38, 0xf4, 0x92, 0xec, 0xce, 0xfc, 0xde, 0x7b, 0xbf, 0xf7, 0x7b, 0x6f, 0xde, 0xac, 0x61, - 0xd5, 0xde, 0xb7, 0xf7, 0x7a, 0x3e, 0xe5, 0xd4, 0xa2, 0xdd, 0x7a, 0x1f, 0x05, 0x5d, 0x5e, 0xe7, - 0x7b, 0xa6, 0x58, 0x51, 0xd5, 0xf1, 0x4d, 0x53, 0x6c, 0x6a, 0x67, 0x2c, 0xca, 0x5c, 0xca, 0xda, - 0x62, 0xb9, 0x2e, 0x5f, 0x24, 0x5c, 0x3b, 0x2d, 0xdf, 0xea, 0x2e, 0x73, 0xea, 0xfd, 0xab, 0xe1, - 0xbf, 0x68, 0xe3, 0x72, 0x22, 0x08, 0x0b, 0x76, 0x91, 0x65, 0xd1, 0xc0, 0xe3, 0x6c, 0xec, 0x39, - 0x82, 0xd6, 0x72, 0xf8, 0xf4, 0x90, 0x8f, 0xdc, 0x61, 0x10, 0x3d, 0x07, 0xc0, 0x3a, 0xc8, 0xc7, - 0x13, 0xf6, 0xc5, 0xdf, 0x68, 0xbf, 0xe2, 0x50, 0x87, 0x4a, 0xf2, 0xe1, 0x93, 0x5c, 0x35, 0xfe, - 0x56, 0xe0, 0x54, 0x83, 0x39, 0xb7, 0x71, 0x8f, 0x32, 0xc2, 0xef, 0xd2, 0x06, 0x76, 0x90, 0xb0, - 0x52, 0xdf, 0x81, 0xa5, 0x11, 0xc9, 0x36, 0xb1, 0xab, 0xca, 0x9a, 0xb2, 0x7e, 0xfc, 0xda, 0x25, - 0x33, 0xa1, 0xcd, 0x58, 0x4e, 0x66, 0x2b, 0x7e, 0xbe, 0x63, 0x37, 0xcb, 0x6c, 0xec, 0x4d, 0xa5, - 0xb0, 0x7c, 0x3f, 0xa0, 0x1c, 0xb7, 0xef, 0x07, 0xc8, 0xe3, 0x81, 0xcb, 0xaa, 0xa5, 0x35, 0x65, - 0xbd, 0xbc, 0xb5, 0xfd, 0xe8, 0x49, 0x6d, 0xee, 0x8f, 0x27, 0xb5, 0x9b, 0x0e, 0xe1, 0x9d, 0x60, - 0xd7, 0xb4, 0xa8, 0x5b, 0x4f, 0xe6, 0x71, 0x63, 0xc3, 0xea, 0x20, 0xe2, 0xd5, 0xe3, 0x15, 0x9b, - 0xef, 0xf7, 0x30, 0x33, 0x5b, 0xd8, 0x27, 0xa8, 0x4b, 0xbe, 0x40, 0xbb, 0x5d, 0x7c, 0xc7, 0xe3, - 0xcd, 0x25, 0xe1, 0x7f, 0x27, 0x72, 0xbf, 0xa9, 0x7e, 0xfd, 0xd7, 0x4f, 0x2f, 0x25, 0x13, 0x30, - 0x08, 0x9c, 0xcb, 0x4d, 0xb5, 0x89, 0x59, 0x8f, 0x7a, 0x0c, 0xab, 0xdb, 0xb0, 0xe4, 0x12, 0x8f, - 0x63, 0xbb, 0x2d, 0x84, 0x65, 0x51, 0xca, 0xe7, 0xcc, 0x6c, 0x3b, 0x98, 0xef, 0x05, 0x6e, 0x4b, - 0x80, 0xb6, 0x9e, 0x0b, 0x73, 0x68, 0x96, 0xa5, 0xa5, 0x5c, 0x33, 0x7e, 0x29, 0x41, 0xb5, 0xc1, - 0x9c, 0x8f, 0x09, 0xef, 0xd8, 0x3e, 0x7a, 0xf0, 0xb6, 0x4f, 0xdd, 0x91, 0xb2, 0x3b, 0x33, 0x29, - 0x3b, 0x8c, 0x97, 0xd0, 0xf7, 0x4d, 0x58, 0x88, 0x28, 0x97, 0xa6, 0xa7, 0x1c, 0x99, 0xa8, 0x7d, - 0x50, 0x5d, 0xe2, 0xb5, 0x53, 0x05, 0x9a, 0xff, 0x8f, 0x0b, 0x74, 0xc2, 0x25, 0xde, 0xce, 0xbf, - 0xd6, 0xe8, 0x07, 0x05, 0xd6, 0x8a, 0x84, 0x8b, 0xeb, 0x94, 0xed, 0x26, 0xe5, 0x48, 0xbb, 0xc9, - 0xf8, 0x55, 0x11, 0xad, 0xf3, 0x61, 0xcf, 0x46, 0x1c, 0xdf, 0xc6, 0xf7, 0x42, 0x36, 0x61, 0x2e, - 0xc4, 0x73, 0x3e, 0x10, 0x67, 0x54, 0x7d, 0x15, 0x16, 0x51, 0xc0, 0x3b, 0xd4, 0x27, 0x7c, 0x5f, - 0xb0, 0x59, 0xdc, 0xaa, 0xfe, 0xf6, 0xf3, 0x46, 0x25, 0x9a, 0x13, 0xb7, 0x6c, 0xdb, 0xc7, 0x8c, - 0xb5, 0xb8, 0x4f, 0x3c, 0xa7, 0x39, 0x82, 0xaa, 0x9f, 0xc2, 0x0b, 0xb6, 0xf4, 0x27, 0xf4, 0x27, - 0x9e, 0xd3, 0x96, 0xa7, 0x3e, 0x2a, 0xe4, 0xf9, 0xbc, 0x42, 0x26, 0x42, 0x47, 0xc5, 0xac, 0xd8, - 0x39, 0xb4, 0x36, 0x97, 0x43, 0x89, 0x47, 0xe1, 0x8c, 0x17, 0xe1, 0xe2, 0xc4, 0x3c, 0x86, 0x12, - 0x1b, 0x03, 0x05, 0x4e, 0x36, 0x98, 0xd3, 0xc2, 0xfc, 0xa3, 0x10, 0x34, 0x63, 0x96, 0x6f, 0xc1, - 0xf3, 0x82, 0x79, 0xd8, 0xec, 0x32, 0xaf, 0xd5, 0xbc, 0xbc, 0x44, 0xa8, 0xb8, 0xc3, 0x8f, 0xf5, - 0xe5, 0xab, 0xba, 0x0d, 0x65, 0x69, 0x1d, 0x29, 0x33, 0x2f, 0x3c, 0xd4, 0x0a, 0x3d, 0x24, 0x74, - 0x39, 0xde, 0x1f, 0x2d, 0x65, 0xe4, 0x58, 0x85, 0x33, 0x99, 0x24, 0x63, 0x09, 0xbe, 0x82, 0x95, - 0x50, 0x2b, 0xaf, 0x4b, 0xad, 0xcf, 0xe5, 0xb9, 0x79, 0xea, 0xfc, 0x2f, 0xc0, 0x12, 0x7d, 0xe0, - 0x61, 0xbf, 0x8d, 0x24, 0x42, 0x88, 0xb0, 0xd8, 0x2c, 0x8b, 0xc5, 0xc8, 0x2a, 0x43, 0xce, 0x81, - 0xd3, 0xa9, 0xf8, 0xf1, 0x01, 0x78, 0x17, 0x56, 0x02, 0xb1, 0xfe, 0x54, 0xa3, 0x6a, 0x79, 0x68, - 0x1b, 0x0d, 0xab, 0x1f, 0x15, 0x99, 0xa9, 0xe8, 0x8a, 0x19, 0x2b, 0xfd, 0x3a, 0x2c, 0x24, 0xfa, - 0x57, 0xcb, 0x23, 0x94, 0x28, 0x50, 0x84, 0xdf, 0x3c, 0x91, 0x4c, 0xbf, 0xaa, 0x18, 0x0f, 0x15, - 0xa9, 0x80, 0xe0, 0xf5, 0x7e, 0x0f, 0xfb, 0x88, 0x53, 0x7f, 0x46, 0x7e, 0x37, 0x53, 0xfc, 0x8c, - 0x3c, 0x7e, 0xc9, 0x58, 0x29, 0x9e, 0xe9, 0x32, 0x9d, 0x87, 0x5a, 0x01, 0xc9, 0xb8, 0x93, 0xbe, - 0x2d, 0x81, 0xda, 0x60, 0xce, 0xad, 0x6e, 0x97, 0x5a, 0x88, 0xe3, 0xbb, 0x54, 0xb4, 0xdb, 0xff, - 0x74, 0x9a, 0xb2, 0xc3, 0x73, 0xfe, 0x68, 0xaf, 0xe2, 0xb4, 0x60, 0x67, 0x41, 0xcb, 0x8a, 0x11, - 0x6b, 0xf5, 0x5d, 0x09, 0x2a, 0x0d, 0xe6, 0x34, 0x31, 0xf7, 0x09, 0xee, 0xe3, 0xf0, 0x02, 0x78, - 0xa6, 0xd5, 0xd2, 0xe1, 0x6c, 0x9e, 0x1c, 0x43, 0xbd, 0xae, 0x3d, 0x3c, 0x06, 0xf3, 0x0d, 0xe6, - 0xa8, 0x3e, 0xa8, 0x39, 0x1f, 0x71, 0x97, 0xf3, 0x52, 0xcd, 0xfd, 0x08, 0xd2, 0xae, 0x4e, 0x0d, - 0x8d, 0xc7, 0xd0, 0x97, 0x70, 0x2a, 0xff, 0x0b, 0xe7, 0xe5, 0x02, 0x5f, 0xb9, 0x68, 0xed, 0xc6, - 0x61, 0xd0, 0x71, 0xf0, 0x6f, 0x14, 0xd0, 0x26, 0x5c, 0xc8, 0x45, 0xe9, 0x14, 0x9b, 0x68, 0x6f, - 0x1c, 0xda, 0x24, 0x26, 0xb3, 0x07, 0x95, 0xdc, 0x31, 0x75, 0x65, 0xa2, 0xcb, 0x24, 0x58, 0xbb, - 0x7e, 0x08, 0x70, 0x1c, 0xf9, 0x1e, 0x2c, 0xa7, 0x2e, 0xe9, 0x8b, 0x05, 0x6e, 0x92, 0x30, 0x6d, - 0x63, 0x2a, 0x58, 0x1c, 0xe7, 0x33, 0x28, 0x27, 0xae, 0xc2, 0x0b, 0x45, 0x64, 0xc7, 0x40, 0xda, - 0x95, 0x29, 0x40, 0x71, 0x04, 0x02, 0x2b, 0xe9, 0x09, 0x79, 0xa9, 0xc0, 0x3e, 0x85, 0xd3, 0xcc, - 0xe9, 0x70, 0x63, 0x1f, 0x90, 0x27, 0xb3, 0x03, 0x66, 0xbd, 0xc0, 0x49, 0x06, 0xa9, 0xbd, 0x32, - 0x2d, 0x72, 0x18, 0x70, 0x6b, 0xe7, 0xd1, 0x81, 0xae, 0x3c, 0x3e, 0xd0, 0x95, 0x3f, 0x0f, 0x74, - 0xe5, 0xfb, 0x81, 0x3e, 0xf7, 0x78, 0xa0, 0xcf, 0xfd, 0x3e, 0xd0, 0xe7, 0x3e, 0x79, 0x6d, 0xfa, - 0x01, 0xb2, 0x37, 0xfc, 0x99, 0x1a, 0xce, 0x91, 0xdd, 0x05, 0xb1, 0x7e, 0xfd, 0x9f, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x2c, 0x21, 0xa9, 0x27, 0xc9, 0x0e, 0x00, 0x00, + 0x14, 0xcf, 0xd8, 0x28, 0x25, 0xaf, 0x76, 0xd2, 0xae, 0x5c, 0xea, 0x6e, 0x5a, 0x3b, 0x75, 0xd5, + 0x92, 0x52, 0xb2, 0xa6, 0x7f, 0xc4, 0x9f, 0xc2, 0xa1, 0x8d, 0x2a, 0x94, 0x0a, 0x5c, 0x88, 0x5d, + 0x40, 0x42, 0x42, 0x66, 0xe2, 0x9d, 0xae, 0x47, 0x78, 0x77, 0x9c, 0x9d, 0x59, 0x37, 0x01, 0x89, + 0x03, 0x47, 0x10, 0x12, 0x12, 0xe2, 0x13, 0xf4, 0x0b, 0x70, 0x40, 0x7c, 0x04, 0xd4, 0x63, 0xc5, + 0x09, 0x71, 0xa8, 0x50, 0x72, 0x40, 0x5c, 0xf9, 0x04, 0x68, 0x67, 0xd6, 0x6b, 0xaf, 0x77, 0x36, + 0x38, 0x75, 0x2b, 0x0e, 0x5c, 0x92, 0x9d, 0x37, 0xbf, 0xf7, 0xef, 0xf7, 0xde, 0xbc, 0x19, 0xc3, + 0xb2, 0xbd, 0x6b, 0xef, 0xf4, 0x7d, 0x26, 0x58, 0x87, 0xf5, 0xea, 0x03, 0x1c, 0xf4, 0x44, 0x5d, + 0xec, 0x58, 0x52, 0x62, 0x18, 0xe3, 0x9b, 0x96, 0xdc, 0x34, 0x4f, 0x75, 0x18, 0x77, 0x19, 0x6f, + 0x4b, 0x71, 0x5d, 0x2d, 0x14, 0xdc, 0x3c, 0xa9, 0x56, 0x75, 0x97, 0x3b, 0xf5, 0xc1, 0xe5, 0xf0, + 0x5f, 0xb4, 0x71, 0x31, 0xe1, 0x84, 0x07, 0x5b, 0xb8, 0xd3, 0x61, 0x81, 0x27, 0xf8, 0xd8, 0x77, + 0x04, 0xad, 0x6a, 0xe2, 0xe9, 0x63, 0x1f, 0xbb, 0x43, 0x27, 0x15, 0x0d, 0x80, 0x77, 0xb1, 0x4f, + 0x0e, 0xd8, 0x97, 0x7f, 0xa3, 0xfd, 0x92, 0xc3, 0x1c, 0xa6, 0x82, 0x0f, 0xbf, 0x94, 0xb4, 0xf6, + 0x17, 0x82, 0x13, 0x0d, 0xee, 0xdc, 0x22, 0x7d, 0xc6, 0xa9, 0xb8, 0xcb, 0x1a, 0xc4, 0xc1, 0x52, + 0xcb, 0x78, 0x07, 0x8a, 0xa3, 0x20, 0xdb, 0xd4, 0x2e, 0xa3, 0x15, 0xb4, 0x7a, 0xf4, 0xca, 0x05, + 0x2b, 0xc1, 0xcd, 0x58, 0x4e, 0x56, 0x2b, 0xfe, 0xbe, 0x6d, 0x37, 0x0b, 0x7c, 0x6c, 0x65, 0x30, + 0x58, 0xdc, 0x0e, 0x98, 0x20, 0xed, 0xed, 0x00, 0x7b, 0x22, 0x70, 0x79, 0x39, 0xb7, 0x82, 0x56, + 0x0b, 0xeb, 0x1b, 0x0f, 0x1f, 0x57, 0xe7, 0x7e, 0x7f, 0x5c, 0xbd, 0xe1, 0x50, 0xd1, 0x0d, 0xb6, + 0xac, 0x0e, 0x73, 0xeb, 0xc9, 0x3c, 0xae, 0xad, 0x75, 0xba, 0x98, 0x7a, 0xf5, 0x58, 0x62, 0x8b, + 0xdd, 0x3e, 0xe1, 0x56, 0x8b, 0xf8, 0x14, 0xf7, 0xe8, 0xe7, 0x78, 0xab, 0x47, 0x6e, 0x7b, 0xa2, + 0x59, 0x94, 0xf6, 0x37, 0x23, 0xf3, 0xd7, 0x8d, 0xaf, 0xfe, 0xfc, 0xf1, 0xa5, 0x64, 0x02, 0x35, + 0x0a, 0x67, 0xb4, 0xa9, 0x36, 0x09, 0xef, 0x33, 0x8f, 0x13, 0x63, 0x03, 0x8a, 0x2e, 0xf5, 0x04, + 0xb1, 0xdb, 0x92, 0x58, 0x1e, 0xa5, 0x7c, 0xc6, 0x4a, 0xb7, 0x83, 0x75, 0x27, 0x70, 0x5b, 0x12, + 0xb4, 0xfe, 0x5c, 0x98, 0x43, 0xb3, 0xa0, 0x34, 0x95, 0xac, 0xf6, 0x73, 0x0e, 0xca, 0x0d, 0xee, + 0x7c, 0x44, 0x45, 0xd7, 0xf6, 0xf1, 0xfd, 0xb7, 0x7d, 0xe6, 0x8e, 0x98, 0xdd, 0x9c, 0x89, 0xd9, + 0xa1, 0xbf, 0x04, 0xbf, 0x6f, 0xc2, 0x7c, 0x14, 0x72, 0x6e, 0xfa, 0x90, 0x23, 0x15, 0x63, 0x00, + 0x86, 0x4b, 0xbd, 0xf6, 0x44, 0x81, 0xf2, 0x4f, 0xb9, 0x40, 0xc7, 0x5c, 0xea, 0x6d, 0xfe, 0x6b, + 0x8d, 0xbe, 0x47, 0xb0, 0x92, 0x45, 0x5c, 0x5c, 0xa7, 0x74, 0x37, 0xa1, 0x67, 0xda, 0x4d, 0xb5, + 0x5f, 0x90, 0x6c, 0x9d, 0x0f, 0xfa, 0x36, 0x16, 0xe4, 0x16, 0xb9, 0x17, 0x46, 0x13, 0xe6, 0x42, + 0x3d, 0xe7, 0x7d, 0x79, 0x46, 0x8d, 0x57, 0x61, 0x01, 0x07, 0xa2, 0xcb, 0x7c, 0x2a, 0x76, 0x65, + 0x34, 0x0b, 0xeb, 0xe5, 0x5f, 0x7f, 0x5a, 0x2b, 0x45, 0x73, 0xe2, 0xa6, 0x6d, 0xfb, 0x84, 0xf3, + 0x96, 0xf0, 0xa9, 0xe7, 0x34, 0x47, 0x50, 0xe3, 0x13, 0x78, 0xc1, 0x56, 0xf6, 0x24, 0xff, 0xd4, + 0x73, 0xda, 0xea, 0xd4, 0x47, 0x85, 0x3c, 0xab, 0x2b, 0x64, 0xc2, 0x75, 0x54, 0xcc, 0x92, 0xad, + 0x09, 0xeb, 0xfa, 0x62, 0x48, 0xf1, 0xc8, 0x5d, 0xed, 0x45, 0x38, 0x7f, 0x60, 0x1e, 0x43, 0x8a, + 0x6b, 0xfb, 0x08, 0x8e, 0x37, 0xb8, 0xd3, 0x22, 0xe2, 0xc3, 0x10, 0x34, 0x63, 0x96, 0x6f, 0xc1, + 0xf3, 0x32, 0xf2, 0xb0, 0xd9, 0x55, 0x5e, 0xcb, 0xba, 0xbc, 0xa4, 0xab, 0xb8, 0xc3, 0x8f, 0x0c, + 0xd4, 0xd2, 0xd8, 0x80, 0x82, 0xd2, 0x8e, 0x98, 0xc9, 0x4b, 0x0b, 0xd5, 0x4c, 0x0b, 0x09, 0x5e, + 0x8e, 0x0e, 0x46, 0xa2, 0x14, 0x1d, 0xcb, 0x70, 0x2a, 0x95, 0x64, 0x4c, 0xc1, 0x97, 0xb0, 0x14, + 0x72, 0xe5, 0xf5, 0x58, 0xe7, 0x33, 0x75, 0x6e, 0x9e, 0x38, 0xff, 0x73, 0x50, 0x64, 0xf7, 0x3d, + 0xe2, 0xb7, 0xb1, 0x42, 0x48, 0x12, 0x16, 0x9a, 0x05, 0x29, 0x8c, 0xb4, 0x52, 0xc1, 0x39, 0x70, + 0x72, 0xc2, 0x7f, 0x7c, 0x00, 0xde, 0x85, 0xa5, 0x40, 0xca, 0x9f, 0x68, 0x54, 0x2d, 0x0e, 0x75, + 0xa3, 0x61, 0xf5, 0x00, 0x29, 0x4f, 0xb2, 0x2b, 0xde, 0xeb, 0x13, 0x1f, 0x0b, 0xe6, 0xcf, 0x58, + 0xf1, 0x1b, 0x30, 0x9f, 0xe8, 0xe3, 0x9a, 0x2e, 0xb0, 0xa4, 0xaf, 0xe1, 0x54, 0xea, 0xeb, 0x6b, + 0x75, 0x16, 0xaa, 0x19, 0x41, 0xc6, 0x15, 0xfb, 0x26, 0x07, 0x46, 0x83, 0x3b, 0x37, 0x7b, 0x3d, + 0xd6, 0xc1, 0x82, 0xdc, 0x65, 0xb2, 0xac, 0xff, 0x51, 0xd7, 0xa6, 0x87, 0x54, 0xfe, 0xd9, 0x5e, + 0x79, 0x93, 0x84, 0x9d, 0x06, 0x33, 0x4d, 0x46, 0xcc, 0xd5, 0xb7, 0x39, 0x28, 0x35, 0xb8, 0xd3, + 0x24, 0xc2, 0xa7, 0x64, 0x40, 0xc2, 0x41, 0xfb, 0xbf, 0x66, 0xab, 0x02, 0xa7, 0x75, 0x74, 0xc4, + 0x7c, 0xfd, 0x80, 0xd4, 0x38, 0x90, 0xfd, 0x37, 0xe3, 0xe1, 0x78, 0x7d, 0xe2, 0x70, 0x98, 0x3a, + 0xa2, 0xb4, 0x87, 0xe2, 0x58, 0x32, 0xea, 0x32, 0xaa, 0xfd, 0x8d, 0xe4, 0x4b, 0x63, 0x38, 0xc3, + 0x9e, 0xce, 0xad, 0x34, 0x5b, 0x2d, 0xef, 0xa8, 0x5a, 0x8e, 0xdd, 0x65, 0xf9, 0xc3, 0xdd, 0x65, + 0xc5, 0xed, 0xc4, 0x25, 0x96, 0x4a, 0xfa, 0xca, 0x83, 0x23, 0x90, 0x6f, 0x70, 0xc7, 0xf0, 0xc1, + 0xd0, 0xbc, 0x5c, 0x2f, 0xea, 0xfc, 0x68, 0x5f, 0x7e, 0xe6, 0xe5, 0xa9, 0xa1, 0xf1, 0xec, 0xfd, + 0x02, 0x4e, 0xe8, 0x9f, 0x75, 0x2f, 0x67, 0xd8, 0xd2, 0xa2, 0xcd, 0x6b, 0x87, 0x41, 0xc7, 0xce, + 0xbf, 0x46, 0x60, 0x1e, 0xf0, 0x0a, 0xc9, 0x4a, 0x27, 0x5b, 0xc5, 0x7c, 0xe3, 0xd0, 0x2a, 0x71, + 0x30, 0x3b, 0x50, 0xd2, 0xde, 0x19, 0x97, 0x0e, 0x34, 0x99, 0x04, 0x9b, 0x57, 0x0f, 0x01, 0x8e, + 0x3d, 0xdf, 0x83, 0xc5, 0x89, 0x97, 0xc9, 0xf9, 0x0c, 0x33, 0x49, 0x98, 0xb9, 0x36, 0x15, 0x2c, + 0xf6, 0xf3, 0x29, 0x14, 0x12, 0xf7, 0xff, 0xb9, 0xac, 0x60, 0xc7, 0x40, 0xe6, 0xa5, 0x29, 0x40, + 0xb1, 0x07, 0x0a, 0x4b, 0x93, 0xd7, 0xd5, 0x85, 0x0c, 0xfd, 0x09, 0x9c, 0x69, 0x4d, 0x87, 0x1b, + 0x7b, 0x35, 0x1f, 0x4f, 0x4f, 0xfb, 0xd5, 0x0c, 0x23, 0x29, 0xa4, 0xf9, 0xca, 0xb4, 0xc8, 0xa1, + 0xc3, 0xf5, 0xcd, 0x87, 0x7b, 0x15, 0xf4, 0x68, 0xaf, 0x82, 0xfe, 0xd8, 0xab, 0xa0, 0xef, 0xf6, + 0x2b, 0x73, 0x8f, 0xf6, 0x2b, 0x73, 0xbf, 0xed, 0x57, 0xe6, 0x3e, 0x7e, 0x6d, 0xfa, 0x69, 0xbe, + 0x33, 0xfc, 0x6d, 0x1e, 0x0e, 0xf5, 0xad, 0x79, 0x29, 0xbf, 0xfa, 0x4f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xf9, 0x54, 0x20, 0x45, 0xbe, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1660,46 +1729,6 @@ func (m *MsgUnlockSharesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *MsgUpdateParams) 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 *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - 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 *MsgUpdateOperatorParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1909,44 +1938,134 @@ func (m *MsgRetrieveFromVaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgDepositToMegavault) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.SubaccountId != nil { - l = m.SubaccountId.Size() - n += 1 + l + sovTx(uint64(l)) - } - l = m.QuoteQuantums.Size() - n += 1 + l + sovTx(uint64(l)) - return n + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgDepositToMegavaultResponse) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = m.MintedShares.Size() - n += 1 + l + sovTx(uint64(l)) - return n -} - -func (m *MsgWithdrawFromMegavault) Size() (n int) { + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + 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 *MsgSetVaultQuotingParams) 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 *MsgSetVaultQuotingParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetVaultQuotingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.QuotingParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.VaultId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + 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 encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgDepositToMegavault) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SubaccountId != nil { + l = m.SubaccountId.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = m.QuoteQuantums.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgDepositToMegavaultResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.MintedShares.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawFromMegavault) Size() (n int) { if m == nil { return 0 } @@ -2050,7 +2169,7 @@ func (m *MsgUnlockSharesResponse) Size() (n int) { return n } -func (m *MsgUpdateParams) Size() (n int) { +func (m *MsgUpdateOperatorParams) Size() (n int) { if m == nil { return 0 } @@ -2065,7 +2184,16 @@ func (m *MsgUpdateParams) Size() (n int) { return n } -func (m *MsgUpdateOperatorParams) Size() (n int) { +func (m *MsgUpdateOperatorParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgAllocateToVault) Size() (n int) { if m == nil { return 0 } @@ -2075,12 +2203,14 @@ func (m *MsgUpdateOperatorParams) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = m.Params.Size() + l = m.VaultId.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.QuoteQuantums.Size() n += 1 + l + sovTx(uint64(l)) return n } -func (m *MsgUpdateOperatorParamsResponse) Size() (n int) { +func (m *MsgAllocateToVaultResponse) Size() (n int) { if m == nil { return 0 } @@ -2089,7 +2219,7 @@ func (m *MsgUpdateOperatorParamsResponse) Size() (n int) { return n } -func (m *MsgAllocateToVault) Size() (n int) { +func (m *MsgRetrieveFromVault) Size() (n int) { if m == nil { return 0 } @@ -2106,7 +2236,7 @@ func (m *MsgAllocateToVault) Size() (n int) { return n } -func (m *MsgAllocateToVaultResponse) Size() (n int) { +func (m *MsgRetrieveFromVaultResponse) Size() (n int) { if m == nil { return 0 } @@ -2115,7 +2245,7 @@ func (m *MsgAllocateToVaultResponse) Size() (n int) { return n } -func (m *MsgRetrieveFromVault) Size() (n int) { +func (m *MsgUpdateParams) Size() (n int) { if m == nil { return 0 } @@ -2125,19 +2255,25 @@ func (m *MsgRetrieveFromVault) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = m.VaultId.Size() - n += 1 + l + sovTx(uint64(l)) - l = m.QuoteQuantums.Size() + l = m.Params.Size() n += 1 + l + sovTx(uint64(l)) return n } -func (m *MsgRetrieveFromVaultResponse) Size() (n int) { +func (m *MsgSetVaultQuotingParams) 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)) + } + l = m.VaultId.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.QuotingParams.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -3141,7 +3277,7 @@ func (m *MsgUnlockSharesResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3164,10 +3300,10 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateOperatorParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateOperatorParams: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3256,7 +3392,7 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateOperatorParamsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3279,10 +3415,60 @@ func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateOperatorParams: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateOperatorParamsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateOperatorParams: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateOperatorParamsResponse: 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 (m *MsgAllocateToVault) 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: MsgAllocateToVault: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAllocateToVault: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3319,7 +3505,7 @@ func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field VaultId", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3346,7 +3532,40 @@ func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.VaultId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuoteQuantums", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.QuoteQuantums.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3371,7 +3590,7 @@ func (m *MsgUpdateOperatorParams) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateOperatorParamsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgAllocateToVaultResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3394,10 +3613,10 @@ func (m *MsgUpdateOperatorParamsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateOperatorParamsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAllocateToVaultResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateOperatorParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAllocateToVaultResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -3421,7 +3640,7 @@ func (m *MsgUpdateOperatorParamsResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAllocateToVault) Unmarshal(dAtA []byte) error { +func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3444,10 +3663,10 @@ func (m *MsgAllocateToVault) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAllocateToVault: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRetrieveFromVault: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAllocateToVault: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRetrieveFromVault: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3569,7 +3788,7 @@ func (m *MsgAllocateToVault) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAllocateToVaultResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRetrieveFromVaultResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3592,10 +3811,10 @@ func (m *MsgAllocateToVaultResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAllocateToVaultResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRetrieveFromVaultResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAllocateToVaultResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRetrieveFromVaultResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -3619,7 +3838,7 @@ func (m *MsgAllocateToVaultResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3642,10 +3861,10 @@ func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRetrieveFromVault: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRetrieveFromVault: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3682,7 +3901,7 @@ func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VaultId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3709,40 +3928,7 @@ func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.VaultId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field QuoteQuantums", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.QuoteQuantums.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3767,7 +3953,7 @@ func (m *MsgRetrieveFromVault) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRetrieveFromVaultResponse) Unmarshal(dAtA []byte) error { +func (m *MsgSetVaultQuotingParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3790,12 +3976,110 @@ func (m *MsgRetrieveFromVaultResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRetrieveFromVaultResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgSetVaultQuotingParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRetrieveFromVaultResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgSetVaultQuotingParams: 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 != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VaultId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.VaultId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuotingParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.QuotingParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 6189e19d4bc05dcbd60c9c5b50eea5f12829afb9 Mon Sep 17 00:00:00 2001 From: Tian Date: Fri, 27 Sep 2024 17:33:42 -0400 Subject: [PATCH 053/120] initialize megavault module account in 7.0.0 upgrade handler (#2394) Co-authored-by: Vincent Chau <99756290+vincentwschau@users.noreply.github.com> --- protocol/app/upgrades.go | 1 + protocol/app/upgrades/v7.0.0/upgrade.go | 75 +++++++++++++++++++ .../upgrades/v7.0.0/upgrade_container_test.go | 23 +++++- 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/protocol/app/upgrades.go b/protocol/app/upgrades.go index df4bf3eb38..3103802ac6 100644 --- a/protocol/app/upgrades.go +++ b/protocol/app/upgrades.go @@ -30,6 +30,7 @@ func (app *App) setupUpgradeHandlers() { v7_0_0.CreateUpgradeHandler( app.ModuleManager, app.configurator, + app.AccountKeeper, app.PricesKeeper, app.VaultKeeper, ), diff --git a/protocol/app/upgrades/v7.0.0/upgrade.go b/protocol/app/upgrades/v7.0.0/upgrade.go index d5a0b8e970..afc87cfada 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade.go +++ b/protocol/app/upgrades/v7.0.0/upgrade.go @@ -8,6 +8,8 @@ import ( upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" @@ -20,6 +22,75 @@ const ( QUOTE_QUANTUMS_PER_MEGAVAULT_SHARE = 1_000_000 ) +var ( + ModuleAccsToInitialize = []string{ + vaulttypes.MegavaultAccountName, + } +) + +// This module account initialization logic is copied from v3.0.0 upgrade handler. +func initializeModuleAccs(ctx sdk.Context, ak authkeeper.AccountKeeper) { + for _, modAccName := range ModuleAccsToInitialize { + // Get module account and relevant permissions from the accountKeeper. + addr, perms := ak.GetModuleAddressAndPermissions(modAccName) + if addr == nil { + panic(fmt.Sprintf( + "Did not find %v in `ak.GetModuleAddressAndPermissions`. This is not expected. Skipping.", + modAccName, + )) + } + + // Try to get the account in state. + acc := ak.GetAccount(ctx, addr) + if acc != nil { + // Account has been initialized. + macc, isModuleAccount := acc.(sdk.ModuleAccountI) + if isModuleAccount { + // Module account was correctly initialized. Skipping + ctx.Logger().Info(fmt.Sprintf( + "module account %+v was correctly initialized. No-op", + macc, + )) + continue + } + // Module account has been initialized as a BaseAccount. Change to module account. + // Note: We need to get the base account to retrieve its account number, and convert it + // in place into a module account. + baseAccount, ok := acc.(*authtypes.BaseAccount) + if !ok { + panic(fmt.Sprintf( + "cannot cast %v into a BaseAccount, acc = %+v", + modAccName, + acc, + )) + } + newModuleAccount := authtypes.NewModuleAccount( + baseAccount, + modAccName, + perms..., + ) + ak.SetModuleAccount(ctx, newModuleAccount) + ctx.Logger().Info(fmt.Sprintf( + "Successfully converted %v to module account in state: %+v", + modAccName, + newModuleAccount, + )) + continue + } + + // Account has not been initialized at all. Initialize it as module. + // Implementation taken from + // https://github.com/dydxprotocol/cosmos-sdk/blob/bdf96fdd/x/auth/keeper/keeper.go#L213 + newModuleAccount := authtypes.NewEmptyModuleAccount(modAccName, perms...) + maccI := (ak.NewAccount(ctx, newModuleAccount)).(sdk.ModuleAccountI) // this set the account number + ak.SetModuleAccount(ctx, maccI) + ctx.Logger().Info(fmt.Sprintf( + "Successfully initialized module account in state: %+v", + newModuleAccount, + )) + } +} + func initCurrencyPairIDCache(ctx sdk.Context, k pricestypes.PricesKeeper) { marketParams := k.GetAllMarketParams(ctx) for _, mp := range marketParams { @@ -126,6 +197,7 @@ func migrateVaultSharesToMegavaultShares(ctx sdk.Context, k vaultkeeper.Keeper) func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, + accountKeeper authkeeper.AccountKeeper, pricesKeeper pricestypes.PricesKeeper, vaultKeeper vaultkeeper.Keeper, ) upgradetypes.UpgradeHandler { @@ -133,6 +205,9 @@ func CreateUpgradeHandler( sdkCtx := lib.UnwrapSDKContext(ctx, "app/upgrades") sdkCtx.Logger().Info(fmt.Sprintf("Running %s Upgrade...", UpgradeName)) + // Initialize module accounts. + initializeModuleAccs(sdkCtx, accountKeeper) + // Initialize the currency pair ID cache for all existing market params. initCurrencyPairIDCache(sdkCtx, pricesKeeper) diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go index ccc0c79883..dc8ef454ff 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/gogoproto/proto" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" v_7_0_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v7.0.0" "github.com/dydxprotocol/v4-chain/protocol/dtypes" "github.com/dydxprotocol/v4-chain/protocol/testing/containertest" @@ -48,9 +49,12 @@ func preUpgradeChecks(node *containertest.Node, t *testing.T) { } func postUpgradeChecks(node *containertest.Node, t *testing.T) { - // Add test for your upgrade handler logic below + // Check that vault quoting params are successfully migrated to vault params. postUpgradeVaultParamsCheck(node, t) + // Check that vault shares are successfully migrated to megavault shares. postUpgradeMegavaultSharesCheck(node, t) + // Check that megavault module account is successfully initialized. + postUpgradeMegavaultModuleAccCheck(node, t) // Check that the affiliates module has been initialized with the default tiers. postUpgradeAffiliatesModuleTiersCheck(node, t) @@ -182,3 +186,20 @@ func postUpgradeAffiliatesModuleTiersCheck(node *containertest.Node, t *testing. require.NoError(t, err) require.Equal(t, affiliatestypes.DefaultAffiliateTiers, affiliateTiersResp.Tiers) } + +func postUpgradeMegavaultModuleAccCheck(node *containertest.Node, t *testing.T) { + resp, err := containertest.Query( + node, + authtypes.NewQueryClient, + authtypes.QueryClient.ModuleAccountByName, + &authtypes.QueryModuleAccountByNameRequest{ + Name: vaulttypes.MegavaultAccountName, + }, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + moduleAccResp := authtypes.QueryModuleAccountByNameResponse{} + err = proto.UnmarshalText(resp.String(), &moduleAccResp) + require.NoError(t, err) +} From 2f5a94c9e5f922079ad4aa4b68f9c6f7ede20374 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:36:31 -0400 Subject: [PATCH 054/120] [CT-1203] add clob pair id and subaccount num filters (#2388) --- .../authenticator/authentication_request.go | 36 ++---- .../authenticator/clob_pair_id_filter.go | 112 ++++++++++++++++++ .../authenticator/clob_pair_id_filter_test.go | 111 +++++++++++++++++ .../authenticator/composition_test.go | 47 +++++--- .../x/accountplus/authenticator/constants.go | 5 + .../authenticator/message_filter.go | 29 ++--- .../x/accountplus/authenticator/requests.go | 6 +- .../authenticator/subaccount_filter.go | 110 +++++++++++++++++ .../authenticator/subaccount_filter_test.go | 111 +++++++++++++++++ .../testutils/spy_authenticator.go | 51 ++++++-- 10 files changed, 547 insertions(+), 71 deletions(-) create mode 100644 protocol/x/accountplus/authenticator/clob_pair_id_filter.go create mode 100644 protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go create mode 100644 protocol/x/accountplus/authenticator/constants.go create mode 100644 protocol/x/accountplus/authenticator/subaccount_filter.go create mode 100644 protocol/x/accountplus/authenticator/subaccount_filter_test.go diff --git a/protocol/x/accountplus/authenticator/authentication_request.go b/protocol/x/accountplus/authenticator/authentication_request.go index d7ff749812..7beab1f930 100644 --- a/protocol/x/accountplus/authenticator/authentication_request.go +++ b/protocol/x/accountplus/authenticator/authentication_request.go @@ -7,7 +7,6 @@ import ( authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" @@ -27,13 +26,6 @@ type SignModeData struct { Textual string `json:"sign_mode_textual"` } -// LocalAny holds a message with its type URL and byte value. This is necessary because the type Any fails -// to serialize and deserialize properly in nested contexts. -type LocalAny struct { - TypeURL string `json:"type_url"` - Value []byte `json:"value"` -} - // SimplifiedSignatureData contains lists of signers and their corresponding signatures. type SimplifiedSignatureData struct { Signers []sdk.AccAddress `json:"signers"` @@ -42,12 +34,12 @@ type SimplifiedSignatureData struct { // ExplicitTxData encapsulates key transaction data like chain ID, account info, and messages. type ExplicitTxData struct { - ChainID string `json:"chain_id"` - AccountNumber uint64 `json:"account_number"` - AccountSequence uint64 `json:"sequence"` - TimeoutHeight uint64 `json:"timeout_height"` - Msgs []LocalAny `json:"msgs"` - Memo string `json:"memo"` + ChainID string `json:"chain_id"` + AccountNumber uint64 `json:"account_number"` + AccountSequence uint64 `json:"sequence"` + TimeoutHeight uint64 `json:"timeout_height"` + Msgs []sdk.Msg `json:"msgs"` + Memo string `json:"memo"` } // GetSignerAndSignatures gets an array of signer and an array of signatures from the transaction @@ -131,26 +123,12 @@ func extractExplicitTxData(tx sdk.Tx, signerData authsigning.SignerData) (Explic return ExplicitTxData{}, errorsmod.Wrap(sdkerrors.ErrInvalidType, "failed to cast tx to TxWithMemo") } - // Encode messages as Anys and manually convert them to a struct we can serialize to json for cosmwasm. - txMsgs := tx.GetMsgs() - msgs := make([]LocalAny, len(txMsgs)) - for i, txMsg := range txMsgs { - encodedMsg, err := types.NewAnyWithValue(txMsg) - if err != nil { - return ExplicitTxData{}, errorsmod.Wrap(err, "failed to encode msg") - } - msgs[i] = LocalAny{ - TypeURL: encodedMsg.TypeUrl, - Value: encodedMsg.Value, - } - } - return ExplicitTxData{ ChainID: signerData.ChainID, AccountNumber: signerData.AccountNumber, AccountSequence: signerData.Sequence, TimeoutHeight: timeoutTx.GetTimeoutHeight(), - Msgs: msgs, + Msgs: tx.GetMsgs(), Memo: memoTx.GetMemo(), }, nil } diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go new file mode 100644 index 0000000000..0f5216a880 --- /dev/null +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go @@ -0,0 +1,112 @@ +package authenticator + +import ( + "strconv" + "strings" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" +) + +var _ Authenticator = &ClobPairIdFilter{} + +// ClobPairIdFilter filters incoming messages based on a whitelist of clob pair ids. +// It ensures that only messages with whitelisted clob pair ids are allowed. +type ClobPairIdFilter struct { + whitelist map[uint32]struct{} +} + +// NewClobPairIdFilter creates a new ClobPairIdFilter with the provided EncodingConfig. +func NewClobPairIdFilter() ClobPairIdFilter { + return ClobPairIdFilter{} +} + +// Type returns the type of the authenticator. +func (m ClobPairIdFilter) Type() string { + return "ClobPairIdFilter" +} + +// StaticGas returns the static gas amount for the authenticator. Currently, it's set to zero. +func (m ClobPairIdFilter) StaticGas() uint64 { + return 0 +} + +// Initialize sets up the authenticator with the given configuration, +// which should be a list of clob pair ids separated by a predefined separator. +func (m ClobPairIdFilter) Initialize(config []byte) (Authenticator, error) { + strSlice := strings.Split(string(config), SEPARATOR) + + m.whitelist = make(map[uint32]struct{}) + for _, str := range strSlice { + num, err := strconv.ParseUint(str, 10, 32) + if err != nil { + return nil, err + } + m.whitelist[uint32(num)] = struct{}{} + } + return m, nil +} + +// Track is a no-op in this implementation but can be used to track message handling. +func (m ClobPairIdFilter) Track(ctx sdk.Context, request AuthenticationRequest) error { + return nil +} + +// Authenticate checks if the message's clob pair ids are in the whitelist. +func (m ClobPairIdFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { + // Collect the clob pair ids from the request. + requestOrderIds := make([]uint32, 0) + switch msg := request.Msg.(type) { + case *clobtypes.MsgPlaceOrder: + requestOrderIds = append(requestOrderIds, msg.Order.OrderId.ClobPairId) + case *clobtypes.MsgCancelOrder: + requestOrderIds = append(requestOrderIds, msg.OrderId.ClobPairId) + case *clobtypes.MsgBatchCancel: + for _, batch := range msg.ShortTermCancels { + requestOrderIds = append(requestOrderIds, batch.ClobPairId) + } + default: + // Skip other messages. + return nil + } + + // Make sure all the clob pair ids are in the whitelist. + for _, clobPairId := range requestOrderIds { + if _, ok := m.whitelist[clobPairId]; !ok { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "order id %d not in whitelist %v", + clobPairId, + m.whitelist, + ) + } + } + return nil +} + +// ConfirmExecution confirms the execution of a message. Currently, it always confirms. +func (m ClobPairIdFilter) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { + return nil +} + +// OnAuthenticatorAdded is currently a no-op but can be extended for additional logic when an authenticator is added. +func (m ClobPairIdFilter) OnAuthenticatorAdded( + ctx sdk.Context, + account sdk.AccAddress, + config []byte, + authenticatorId string, +) error { + return nil +} + +// OnAuthenticatorRemoved is a no-op in this implementation but can be used when an authenticator is removed. +func (m ClobPairIdFilter) OnAuthenticatorRemoved( + ctx sdk.Context, + account sdk.AccAddress, + config []byte, + authenticatorId string, +) error { + return nil +} diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go new file mode 100644 index 0000000000..c6d6679f1c --- /dev/null +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go @@ -0,0 +1,111 @@ +package authenticator_test + +import ( + "os" + "testing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + + "github.com/stretchr/testify/suite" +) + +type ClobPairIdFilterTest struct { + BaseAuthenticatorSuite + + ClobPairIdFilter authenticator.ClobPairIdFilter +} + +func TestClobPairIdFilterTest(t *testing.T) { + suite.Run(t, new(ClobPairIdFilterTest)) +} + +func (s *ClobPairIdFilterTest) SetupTest() { + s.SetupKeys() + s.ClobPairIdFilter = authenticator.NewClobPairIdFilter() +} + +func (s *ClobPairIdFilterTest) TearDownTest() { + os.RemoveAll(s.HomeDir) +} + +// TestFilter tests the ClobPairIdFilter with multiple clob messages +func (s *ClobPairIdFilterTest) TestFilter() { + tests := map[string]struct { + whitelist string + msg sdk.Msg + + match bool + }{ + "order place": { + whitelist: "0", + msg: constants.Msg_PlaceOrder_LongTerm, + match: true, + }, + "order cancel": { + whitelist: "0", + msg: constants.Msg_CancelOrder_LongTerm, + match: true, + }, + "order batch cancel": { + whitelist: "0", + msg: constants.Msg_BatchCancel, + match: true, + }, + "order place - fail": { + whitelist: "1", + msg: constants.Msg_PlaceOrder_LongTerm, + match: false, + }, + "order cancel - fail": { + whitelist: "1", + msg: constants.Msg_CancelOrder_LongTerm, + match: false, + }, + "order batch cancel - fail": { + whitelist: "1", + msg: constants.Msg_BatchCancel, + match: false, + }, + } + + for name, tt := range tests { + s.Run(name, func() { + err := s.ClobPairIdFilter.OnAuthenticatorAdded(s.Ctx, sdk.AccAddress{}, []byte(tt.whitelist), "1") + s.Require().NoError(err) + filter, err := s.ClobPairIdFilter.Initialize([]byte(tt.whitelist)) + s.Require().NoError(err) + + ak := s.tApp.App.AccountKeeper + sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() + tx, err := s.GenSimpleTx([]sdk.Msg{tt.msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) + s.Require().NoError(err) + request, err := authenticator.GenerateAuthenticationRequest( + s.Ctx, + s.tApp.App.AppCodec(), + ak, + sigModeHandler, + constants.AliceAccAddress, + constants.AliceAccAddress, + nil, + sdk.NewCoins(), + tt.msg, + tx, + 0, + false, + ) + s.Require().NoError(err) + + err = filter.Authenticate(s.Ctx, request) + if tt.match { + s.Require().NoError(err) + } else { + s.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) + } + }) + } +} diff --git a/protocol/x/accountplus/authenticator/composition_test.go b/protocol/x/accountplus/authenticator/composition_test.go index b2d421b3e5..a3ac5da8cd 100644 --- a/protocol/x/accountplus/authenticator/composition_test.go +++ b/protocol/x/accountplus/authenticator/composition_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" bank "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -16,6 +15,7 @@ import ( storetypes "cosmossdk.io/store/types" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/testutils" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" @@ -65,6 +65,7 @@ func (s *AggregatedAuthenticatorsTest) SetupTest() { Confirm: testutils.Always, } s.spyAuth = testutils.NewSpyAuthenticator( + s.tApp.App.AppCodec(), s.tApp.App.GetKVStoreKey()[types.StoreKey], ) @@ -665,9 +666,6 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { Amount: sdk.NewCoins(sdk.NewInt64Coin("foo", 1)), } - encodedMsg, err := codectypes.NewAnyWithValue(msg) - s.Require().NoError(err, "Should encode Any value successfully") - // mock the authentication request authReq := authenticator.AuthenticationRequest{ AuthenticatorId: tc.id, @@ -675,7 +673,7 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { FeePayer: s.TestAccAddress[0], FeeGranter: nil, Fee: sdk.NewCoins(), - Msg: authenticator.LocalAny{TypeURL: encodedMsg.TypeUrl, Value: encodedMsg.Value}, + Msg: msg, MsgIndex: 0, Signature: []byte{1, 1, 1, 1, 1}, SignModeTxData: authenticator.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, @@ -699,7 +697,11 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { expectedAuthReq := authReq expectedAuthReq.AuthenticatorId = tc.expectedIds[i] - spy := testutils.SpyAuthenticator{KvStoreKey: s.spyAuth.KvStoreKey, Name: name} + spy := testutils.SpyAuthenticator{ + KvStoreKey: s.spyAuth.KvStoreKey, + Name: name, + Cdc: constants.TestEncodingCfg.Codec, + } latestCalls := spy.GetLatestCalls(s.Ctx) spyData, err := json.Marshal(testutils.SpyAuthenticatorData{Name: name}) @@ -713,17 +715,33 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { }, latestCalls.OnAuthenticatorAdded, ) - s.Require().Equal(expectedAuthReq, latestCalls.Authenticate) + s.Require().Equal( + testutils.SpyAuthenticateRequest{ + AuthenticatorId: expectedAuthReq.AuthenticatorId, + Account: expectedAuthReq.Account, + Msg: s.tApp.App.AppCodec().MustMarshal(expectedAuthReq.Msg), + MsgIndex: expectedAuthReq.MsgIndex, + }, + latestCalls.Authenticate, + ) s.Require().Equal( testutils.SpyTrackRequest{ AuthenticatorId: expectedAuthReq.AuthenticatorId, Account: expectedAuthReq.Account, - Msg: expectedAuthReq.Msg, + Msg: s.tApp.App.AppCodec().MustMarshal(expectedAuthReq.Msg), MsgIndex: expectedAuthReq.MsgIndex, }, latestCalls.Track, ) - s.Require().Equal(expectedAuthReq, latestCalls.ConfirmExecution) + s.Require().Equal( + testutils.SpyConfirmExecutionRequest{ + AuthenticatorId: expectedAuthReq.AuthenticatorId, + Account: expectedAuthReq.Account, + Msg: s.tApp.App.AppCodec().MustMarshal(expectedAuthReq.Msg), + MsgIndex: expectedAuthReq.MsgIndex, + }, + latestCalls.ConfirmExecution, + ) s.Require().Equal( testutils.SpyRemoveRequest{ Account: expectedAuthReq.Account, @@ -834,15 +852,12 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOfNotWritingFailedSubAuthState() { Amount: sdk.NewCoins(sdk.NewInt64Coin("foo", 1)), } - encodedMsg, err := codectypes.NewAnyWithValue(msg) - s.Require().NoError(err, "Should encode Any value successfully") - // mock the authentication request authReq := authenticator.AuthenticationRequest{ AuthenticatorId: "1", Account: s.TestAccAddress[0], FeePayer: s.TestAccAddress[0], - Msg: authenticator.LocalAny{TypeURL: encodedMsg.TypeUrl, Value: encodedMsg.Value}, + Msg: msg, MsgIndex: 0, Signature: []byte{1, 1, 1, 1, 1}, SignModeTxData: authenticator.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, @@ -858,7 +873,11 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOfNotWritingFailedSubAuthState() { s.Require().NoError(auth.ConfirmExecution(s.Ctx, authReq)) for i, name := range tc.names { - spy := testutils.SpyAuthenticator{KvStoreKey: s.spyAuth.KvStoreKey, Name: name} + spy := testutils.SpyAuthenticator{ + KvStoreKey: s.spyAuth.KvStoreKey, + Name: name, + Cdc: constants.TestEncodingCfg.Codec, + } latestCalls := spy.GetLatestCalls(s.Ctx) latestConfirmExecuion := latestCalls.ConfirmExecution diff --git a/protocol/x/accountplus/authenticator/constants.go b/protocol/x/accountplus/authenticator/constants.go new file mode 100644 index 0000000000..716f9340ed --- /dev/null +++ b/protocol/x/accountplus/authenticator/constants.go @@ -0,0 +1,5 @@ +package authenticator + +// SEPARATOR is the separator used to split the configuration string. +// This is used by MessageFilter, SubaccountFilter, and ClobPairIdFilter. +const SEPARATOR = "," diff --git a/protocol/x/accountplus/authenticator/message_filter.go b/protocol/x/accountplus/authenticator/message_filter.go index 9f633a69bd..9bb1fb9f93 100644 --- a/protocol/x/accountplus/authenticator/message_filter.go +++ b/protocol/x/accountplus/authenticator/message_filter.go @@ -9,14 +9,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -const SEPARATOR = "," - var _ Authenticator = &MessageFilter{} // MessageFilter filters incoming messages based on a predefined JSON pattern. // It allows for complex pattern matching to support advanced authentication flows. type MessageFilter struct { - msgTypes []string + whitelist map[string]struct{} } // NewMessageFilter creates a new MessageFilter with the provided EncodingConfig. @@ -36,7 +34,12 @@ func (m MessageFilter) StaticGas() uint64 { // Initialize sets up the authenticator with the given data, which should be a valid JSON pattern for message filtering. func (m MessageFilter) Initialize(config []byte) (Authenticator, error) { - m.msgTypes = strings.Split(string(config), SEPARATOR) + strSlice := strings.Split(string(config), SEPARATOR) + + m.whitelist = make(map[string]struct{}) + for _, messageType := range strSlice { + m.whitelist[messageType] = struct{}{} + } return m, nil } @@ -48,17 +51,15 @@ func (m MessageFilter) Track(ctx sdk.Context, request AuthenticationRequest) err // Authenticate checks if the provided message conforms to the set JSON pattern. // It returns an AuthenticationResult based on the evaluation. func (m MessageFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { - for _, msgType := range m.msgTypes { - if request.Msg.TypeURL == msgType { - return nil - } + if _, ok := m.whitelist[sdk.MsgTypeURL(request.Msg)]; !ok { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "message types do not match. Got %s, Expected %v", + sdk.MsgTypeURL(request.Msg), + m.whitelist, + ) } - return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, - "message types do not match. Got %s, Expected %v", - request.Msg.TypeURL, - m.msgTypes, - ) + return nil } // ConfirmExecution confirms the execution of a message. Currently, it always confirms. diff --git a/protocol/x/accountplus/authenticator/requests.go b/protocol/x/accountplus/authenticator/requests.go index f1629f862e..54647a00dc 100644 --- a/protocol/x/accountplus/authenticator/requests.go +++ b/protocol/x/accountplus/authenticator/requests.go @@ -10,7 +10,7 @@ type TrackRequest struct { FeePayer sdk.AccAddress `json:"fee_payer"` FeeGranter sdk.AccAddress `json:"fee_granter,omitempty"` Fee sdk.Coins `json:"fee"` - Msg LocalAny `json:"msg"` + Msg sdk.Msg `json:"msg"` MsgIndex uint64 `json:"msg_index"` AuthenticatorParams []byte `json:"authenticator_params,omitempty"` } @@ -21,7 +21,7 @@ type ConfirmExecutionRequest struct { FeePayer sdk.AccAddress `json:"fee_payer"` FeeGranter sdk.AccAddress `json:"fee_granter,omitempty"` Fee sdk.Coins `json:"fee"` - Msg LocalAny `json:"msg"` + Msg sdk.Msg `json:"msg"` MsgIndex uint64 `json:"msg_index"` AuthenticatorParams []byte `json:"authenticator_params,omitempty"` } @@ -32,7 +32,7 @@ type AuthenticationRequest struct { FeePayer sdk.AccAddress `json:"fee_payer"` FeeGranter sdk.AccAddress `json:"fee_granter,omitempty"` Fee sdk.Coins `json:"fee"` - Msg LocalAny `json:"msg"` + Msg sdk.Msg `json:"msg"` // Since array size is int, and size depends on the system architecture, // we use uint64 to cover all available architectures. diff --git a/protocol/x/accountplus/authenticator/subaccount_filter.go b/protocol/x/accountplus/authenticator/subaccount_filter.go new file mode 100644 index 0000000000..725086f7e1 --- /dev/null +++ b/protocol/x/accountplus/authenticator/subaccount_filter.go @@ -0,0 +1,110 @@ +package authenticator + +import ( + "strconv" + "strings" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" +) + +var _ Authenticator = &SubaccountFilter{} + +// SubaccountFilter filters incoming messages based on a whitelist of subaccount numbers. +// It ensures that only messages with whitelisted subaccount numbers are allowed. +type SubaccountFilter struct { + whitelist map[uint32]struct{} +} + +// NewSubaccountFilter creates a new SubaccountFilter with the provided EncodingConfig. +func NewSubaccountFilter() SubaccountFilter { + return SubaccountFilter{} +} + +// Type returns the type of the authenticator. +func (m SubaccountFilter) Type() string { + return "SubaccountFilter" +} + +// StaticGas returns the static gas amount for the authenticator. Currently, it's set to zero. +func (m SubaccountFilter) StaticGas() uint64 { + return 0 +} + +// Initialize sets up the authenticator with the given data, +// which should be a string of subaccount numbers separated by the specified separator. +func (m SubaccountFilter) Initialize(config []byte) (Authenticator, error) { + strSlice := strings.Split(string(config), SEPARATOR) + + m.whitelist = make(map[uint32]struct{}) + for _, str := range strSlice { + num, err := strconv.ParseUint(str, 10, 32) + if err != nil { + return nil, err + } + m.whitelist[uint32(num)] = struct{}{} + } + return m, nil +} + +// Track is a no-op in this implementation but can be used to track message handling. +func (m SubaccountFilter) Track(ctx sdk.Context, request AuthenticationRequest) error { + return nil +} + +// Authenticate checks if the message's subaccount numbers are in the whitelist. +func (m SubaccountFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { + // Collect the clob pair ids from the request. + requestSubaccountNums := make([]uint32, 0) + switch msg := request.Msg.(type) { + case *clobtypes.MsgPlaceOrder: + requestSubaccountNums = append(requestSubaccountNums, msg.Order.OrderId.SubaccountId.Number) + case *clobtypes.MsgCancelOrder: + requestSubaccountNums = append(requestSubaccountNums, msg.OrderId.SubaccountId.Number) + case *clobtypes.MsgBatchCancel: + requestSubaccountNums = append(requestSubaccountNums, msg.SubaccountId.Number) + default: + // Skip other messages. + return nil + } + + // Make sure all the subaccount numbers are in the whitelist. + for _, subaccountNum := range requestSubaccountNums { + if _, ok := m.whitelist[subaccountNum]; !ok { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "subaccount number %d not in whitelist %v", + subaccountNum, + m.whitelist, + ) + } + } + return nil +} + +// ConfirmExecution confirms the execution of a message. Currently, it always confirms. +func (m SubaccountFilter) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { + return nil +} + +// OnAuthenticatorAdded is currently a no-op but can be extended for additional logic when an authenticator is added. +func (m SubaccountFilter) OnAuthenticatorAdded( + ctx sdk.Context, + account sdk.AccAddress, + config []byte, + authenticatorId string, +) error { + return nil +} + +// OnAuthenticatorRemoved is a no-op in this implementation but can be used when an authenticator is removed. +func (m SubaccountFilter) OnAuthenticatorRemoved( + ctx sdk.Context, + account sdk.AccAddress, + config []byte, + authenticatorId string, +) error { + return nil +} diff --git a/protocol/x/accountplus/authenticator/subaccount_filter_test.go b/protocol/x/accountplus/authenticator/subaccount_filter_test.go new file mode 100644 index 0000000000..dbb703a9f3 --- /dev/null +++ b/protocol/x/accountplus/authenticator/subaccount_filter_test.go @@ -0,0 +1,111 @@ +package authenticator_test + +import ( + "os" + "testing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + + "github.com/stretchr/testify/suite" +) + +type SubaccountFilterTest struct { + BaseAuthenticatorSuite + + SubaccountFilter authenticator.SubaccountFilter +} + +func TestSubaccountFilterTest(t *testing.T) { + suite.Run(t, new(SubaccountFilterTest)) +} + +func (s *SubaccountFilterTest) SetupTest() { + s.SetupKeys() + s.SubaccountFilter = authenticator.NewSubaccountFilter() +} + +func (s *SubaccountFilterTest) TearDownTest() { + os.RemoveAll(s.HomeDir) +} + +// TestFilter tests the SubaccountFilter with multiple clob messages +func (s *SubaccountFilterTest) TestFilter() { + tests := map[string]struct { + whitelist string + msg sdk.Msg + + match bool + }{ + "order place": { + whitelist: "0", + msg: constants.Msg_PlaceOrder_LongTerm, + match: true, + }, + "order cancel": { + whitelist: "0", + msg: constants.Msg_CancelOrder_LongTerm, + match: true, + }, + "order batch cancel": { + whitelist: "0", + msg: constants.Msg_BatchCancel, + match: true, + }, + "order place - fail": { + whitelist: "1", + msg: constants.Msg_PlaceOrder_LongTerm, + match: false, + }, + "order cancel - fail": { + whitelist: "1", + msg: constants.Msg_CancelOrder_LongTerm, + match: false, + }, + "order batch cancel - fail": { + whitelist: "1", + msg: constants.Msg_BatchCancel, + match: false, + }, + } + + for name, tt := range tests { + s.Run(name, func() { + err := s.SubaccountFilter.OnAuthenticatorAdded(s.Ctx, sdk.AccAddress{}, []byte(tt.whitelist), "1") + s.Require().NoError(err) + filter, err := s.SubaccountFilter.Initialize([]byte(tt.whitelist)) + s.Require().NoError(err) + + ak := s.tApp.App.AccountKeeper + sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() + tx, err := s.GenSimpleTx([]sdk.Msg{tt.msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) + s.Require().NoError(err) + request, err := authenticator.GenerateAuthenticationRequest( + s.Ctx, + s.tApp.App.AppCodec(), + ak, + sigModeHandler, + constants.AliceAccAddress, + constants.AliceAccAddress, + nil, + sdk.NewCoins(), + tt.msg, + tx, + 0, + false, + ) + s.Require().NoError(err) + + err = filter.Authenticate(s.Ctx, request) + if tt.match { + s.Require().NoError(err) + } else { + s.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) + } + }) + } +} diff --git a/protocol/x/accountplus/testutils/spy_authenticator.go b/protocol/x/accountplus/testutils/spy_authenticator.go index 0f30b3a9ed..f694f5fd0e 100644 --- a/protocol/x/accountplus/testutils/spy_authenticator.go +++ b/protocol/x/accountplus/testutils/spy_authenticator.go @@ -6,6 +6,7 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -14,11 +15,25 @@ import ( var _ authenticator.Authenticator = &SpyAuthenticator{} +type SpyAuthenticateRequest struct { + AuthenticatorId string `json:"authenticator_id"` + Account sdk.AccAddress `json:"account"` + Msg []byte `json:"msg"` + MsgIndex uint64 `json:"msg_index"` +} + type SpyTrackRequest struct { - AuthenticatorId string `json:"authenticator_id"` - Account sdk.AccAddress `json:"account"` - Msg authenticator.LocalAny `json:"msg"` - MsgIndex uint64 `json:"msg_index"` + AuthenticatorId string `json:"authenticator_id"` + Account sdk.AccAddress `json:"account"` + Msg []byte `json:"msg"` + MsgIndex uint64 `json:"msg_index"` +} + +type SpyConfirmExecutionRequest struct { + AuthenticatorId string `json:"authenticator_id"` + Account sdk.AccAddress `json:"account"` + Msg []byte `json:"msg"` + MsgIndex uint64 `json:"msg_index"` } type SpyAddRequest struct { @@ -34,9 +49,9 @@ type SpyRemoveRequest struct { } type LatestCalls struct { - Authenticate authenticator.AuthenticationRequest + Authenticate SpyAuthenticateRequest Track SpyTrackRequest - ConfirmExecution authenticator.AuthenticationRequest + ConfirmExecution SpyConfirmExecutionRequest OnAuthenticatorAdded SpyAddRequest OnAuthenticatorRemoved SpyRemoveRequest } @@ -62,10 +77,11 @@ type SpyAuthenticator struct { KvStoreKey storetypes.StoreKey Name string Failure FailureFlag + Cdc codec.BinaryCodec } -func NewSpyAuthenticator(kvStoreKey storetypes.StoreKey) SpyAuthenticator { - return SpyAuthenticator{KvStoreKey: kvStoreKey} +func NewSpyAuthenticator(cdc codec.BinaryCodec, kvStoreKey storetypes.StoreKey) SpyAuthenticator { + return SpyAuthenticator{Cdc: cdc, KvStoreKey: kvStoreKey} } func (s SpyAuthenticator) Type() string { @@ -89,7 +105,13 @@ func (s SpyAuthenticator) Initialize(config []byte) (authenticator.Authenticator func (s SpyAuthenticator) Authenticate(ctx sdk.Context, request authenticator.AuthenticationRequest) error { s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { - calls.Authenticate = request + bz := s.Cdc.MustMarshal(request.Msg) + calls.Authenticate = SpyAuthenticateRequest{ + AuthenticatorId: request.AuthenticatorId, + Account: request.Account, + Msg: bz, + MsgIndex: request.MsgIndex, + } return calls }) @@ -101,10 +123,11 @@ func (s SpyAuthenticator) Authenticate(ctx sdk.Context, request authenticator.Au func (s SpyAuthenticator) Track(ctx sdk.Context, request authenticator.AuthenticationRequest) error { s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { + bz := s.Cdc.MustMarshal(request.Msg) calls.Track = SpyTrackRequest{ AuthenticatorId: request.AuthenticatorId, Account: request.Account, - Msg: request.Msg, + Msg: bz, MsgIndex: request.MsgIndex, } return calls @@ -115,7 +138,13 @@ func (s SpyAuthenticator) Track(ctx sdk.Context, request authenticator.Authentic func (s SpyAuthenticator) ConfirmExecution(ctx sdk.Context, request authenticator.AuthenticationRequest) error { // intentionlly call update before check to test state revert s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { - calls.ConfirmExecution = request + bz := s.Cdc.MustMarshal(request.Msg) + calls.ConfirmExecution = SpyConfirmExecutionRequest{ + AuthenticatorId: request.AuthenticatorId, + Account: request.Account, + Msg: bz, + MsgIndex: request.MsgIndex, + } return calls }) From 5282ba0274e089bc882979a6ae8d5bdbb0b4531a Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:46:26 -0400 Subject: [PATCH 055/120] [CT-1237] enable messages and add ante decorator to the chain (#2375) --- protocol/app/ante.go | 17 +++++++++++++---- protocol/app/msgs/all_msgs.go | 10 ++++++++++ protocol/app/msgs/internal_msgs.go | 6 +++++- protocol/app/msgs/internal_msgs_test.go | 4 ++++ protocol/app/msgs/normal_msgs.go | 9 +++++++++ protocol/app/msgs/normal_msgs_test.go | 7 +++++++ protocol/lib/ante/internal_msg.go | 4 ++++ protocol/x/accountplus/ante/circuit_breaker.go | 12 ++++++------ .../x/accountplus/ante/circuit_breaker_test.go | 4 ++-- protocol/x/accountplus/module.go | 10 ++++++++-- protocol/x/accountplus/types/codec.go | 9 +++++++++ 11 files changed, 77 insertions(+), 15 deletions(-) diff --git a/protocol/app/ante.go b/protocol/app/ante.go index 63fc159b60..b00c48e157 100644 --- a/protocol/app/ante.go +++ b/protocol/app/ante.go @@ -122,9 +122,18 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { options.AccountKeeper, *options.AccountplusKeeper, ), - sigVerification: customante.NewSigVerificationDecorator( - options.AccountKeeper, - options.SignModeHandler, + sigVerification: accountplusante.NewCircuitBreakerDecorator( + options.Codec, + accountplusante.NewAuthenticatorDecorator( + options.Codec, + options.AccountplusKeeper, + options.AccountKeeper, + options.SignModeHandler, + ), + customante.NewSigVerificationDecorator( + options.AccountKeeper, + options.SignModeHandler, + ), ), consumeTxSizeGas: ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), deductFee: ante.NewDeductFeeDecorator( @@ -163,7 +172,7 @@ type lockingAnteHandler struct { validateSigCount ante.ValidateSigCountDecorator incrementSequence ante.IncrementSequenceDecorator replayProtection customante.ReplayProtectionDecorator - sigVerification customante.SigVerificationDecorator + sigVerification accountplusante.CircuitBreakerDecorator consumeTxSizeGas ante.ConsumeTxSizeGasDecorator deductFee ante.DeductFeeDecorator setPubKey ante.SetPubKeyDecorator diff --git a/protocol/app/msgs/all_msgs.go b/protocol/app/msgs/all_msgs.go index 1276ccb7cc..d09a39cccd 100644 --- a/protocol/app/msgs/all_msgs.go +++ b/protocol/app/msgs/all_msgs.go @@ -155,6 +155,16 @@ var ( "/dydxprotocol.affiliates.MsgUpdateAffiliateTiersResponse": {}, "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelist": {}, "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelistResponse": {}, + + // accountplus + "/dydxprotocol.accountplus.MsgAddAuthenticator": {}, + "/dydxprotocol.accountplus.MsgAddAuthenticatorResponse": {}, + "/dydxprotocol.accountplus.MsgRemoveAuthenticator": {}, + "/dydxprotocol.accountplus.MsgRemoveAuthenticatorResponse": {}, + "/dydxprotocol.accountplus.MsgSetActiveState": {}, + "/dydxprotocol.accountplus.MsgSetActiveStateResponse": {}, + "/dydxprotocol.accountplus.TxExtension": {}, + // blocktime "/dydxprotocol.blocktime.MsgUpdateDowntimeParams": {}, "/dydxprotocol.blocktime.MsgUpdateDowntimeParamsResponse": {}, diff --git a/protocol/app/msgs/internal_msgs.go b/protocol/app/msgs/internal_msgs.go index 736ef64829..9c0e58f9f6 100644 --- a/protocol/app/msgs/internal_msgs.go +++ b/protocol/app/msgs/internal_msgs.go @@ -16,6 +16,7 @@ import ( ibcclient "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck ibcconn "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/dydxprotocol/v4-chain/protocol/lib" + accountplus "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" affiliates "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" blocktime "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/types" bridge "github.com/dydxprotocol/v4-chain/protocol/x/bridge/types" @@ -106,13 +107,16 @@ var ( // Custom modules InternalMsgSamplesDydxCustom = map[string]sdk.Msg{ - // affiliates "/dydxprotocol.affiliates.MsgUpdateAffiliateTiers": &affiliates.MsgUpdateAffiliateTiers{}, "/dydxprotocol.affiliates.MsgUpdateAffiliateTiersResponse": nil, "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelist": &affiliates.MsgUpdateAffiliateWhitelist{}, "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelistResponse": nil, + // accountplus + "/dydxprotocol.accountplus.MsgSetActiveState": &accountplus.MsgSetActiveState{}, + "/dydxprotocol.accountplus.MsgSetActiveStateResponse": nil, + // blocktime "/dydxprotocol.blocktime.MsgUpdateDowntimeParams": &blocktime.MsgUpdateDowntimeParams{}, "/dydxprotocol.blocktime.MsgUpdateDowntimeParamsResponse": nil, diff --git a/protocol/app/msgs/internal_msgs_test.go b/protocol/app/msgs/internal_msgs_test.go index 25485356a9..70e3549fe5 100644 --- a/protocol/app/msgs/internal_msgs_test.go +++ b/protocol/app/msgs/internal_msgs_test.go @@ -63,6 +63,10 @@ func TestInternalMsgSamples_Gov_Key(t *testing.T) { "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", "/cosmos.upgrade.v1beta1.MsgSoftwareUpgradeResponse", + // accountplus + "/dydxprotocol.accountplus.MsgSetActiveState", + "/dydxprotocol.accountplus.MsgSetActiveStateResponse", + // affiliates "/dydxprotocol.affiliates.MsgUpdateAffiliateTiers", "/dydxprotocol.affiliates.MsgUpdateAffiliateTiersResponse", diff --git a/protocol/app/msgs/normal_msgs.go b/protocol/app/msgs/normal_msgs.go index a6a5bdb08d..2990258712 100644 --- a/protocol/app/msgs/normal_msgs.go +++ b/protocol/app/msgs/normal_msgs.go @@ -17,6 +17,7 @@ import ( ibcconn "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" ibccore "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/dydxprotocol/v4-chain/protocol/lib" + accountplus "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" affiliates "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" clob "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" listing "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" @@ -221,6 +222,14 @@ var ( // affiliates "/dydxprotocol.affiliates.MsgRegisterAffiliate": &affiliates.MsgRegisterAffiliate{}, "/dydxprotocol.affiliates.MsgRegisterAffiliateResponse": nil, + + // accountplus + "/dydxprotocol.accountplus.MsgAddAuthenticator": &accountplus.MsgAddAuthenticator{}, + "/dydxprotocol.accountplus.MsgAddAuthenticatorResponse": nil, + "/dydxprotocol.accountplus.MsgRemoveAuthenticator": &accountplus.MsgRemoveAuthenticator{}, + "/dydxprotocol.accountplus.MsgRemoveAuthenticatorResponse": nil, + "/dydxprotocol.accountplus.TxExtension": nil, + // clob "/dydxprotocol.clob.MsgBatchCancel": &clob.MsgBatchCancel{}, "/dydxprotocol.clob.MsgBatchCancelResponse": nil, diff --git a/protocol/app/msgs/normal_msgs_test.go b/protocol/app/msgs/normal_msgs_test.go index e8f660357c..2ae0015db5 100644 --- a/protocol/app/msgs/normal_msgs_test.go +++ b/protocol/app/msgs/normal_msgs_test.go @@ -118,6 +118,13 @@ func TestNormalMsgs_Key(t *testing.T) { "/cosmos.upgrade.v1beta1.CancelSoftwareUpgradeProposal", "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + // accountplus + "/dydxprotocol.accountplus.MsgAddAuthenticator", + "/dydxprotocol.accountplus.MsgAddAuthenticatorResponse", + "/dydxprotocol.accountplus.MsgRemoveAuthenticator", + "/dydxprotocol.accountplus.MsgRemoveAuthenticatorResponse", + "/dydxprotocol.accountplus.TxExtension", + // affiliates "/dydxprotocol.affiliates.MsgRegisterAffiliate", "/dydxprotocol.affiliates.MsgRegisterAffiliateResponse", diff --git a/protocol/lib/ante/internal_msg.go b/protocol/lib/ante/internal_msg.go index 2fc5754712..4d578d4f10 100644 --- a/protocol/lib/ante/internal_msg.go +++ b/protocol/lib/ante/internal_msg.go @@ -15,6 +15,7 @@ import ( ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcclient "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck ibcconn "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + accountplus "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" affiliates "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" blocktime "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/types" bridge "github.com/dydxprotocol/v4-chain/protocol/x/bridge/types" @@ -71,6 +72,9 @@ func IsInternalMsg(msg sdk.Msg) bool { *upgrade.MsgSoftwareUpgrade, // ------- Custom modules + // accountplus + *accountplus.MsgSetActiveState, + // blocktime *blocktime.MsgUpdateDowntimeParams, diff --git a/protocol/x/accountplus/ante/circuit_breaker.go b/protocol/x/accountplus/ante/circuit_breaker.go index 549461847a..95eebb429a 100644 --- a/protocol/x/accountplus/ante/circuit_breaker.go +++ b/protocol/x/accountplus/ante/circuit_breaker.go @@ -11,15 +11,15 @@ import ( // the existence of `TxExtension`. type CircuitBreakerDecorator struct { cdc codec.BinaryCodec - authenticatorAnteHandlerFlow sdk.AnteHandler - originalAnteHandlerFlow sdk.AnteHandler + authenticatorAnteHandlerFlow sdk.AnteDecorator + originalAnteHandlerFlow sdk.AnteDecorator } // NewCircuitBreakerDecorator creates a new instance of CircuitBreakerDecorator with the provided parameters. func NewCircuitBreakerDecorator( cdc codec.BinaryCodec, - auth sdk.AnteHandler, - classic sdk.AnteHandler, + auth sdk.AnteDecorator, + classic sdk.AnteDecorator, ) CircuitBreakerDecorator { return CircuitBreakerDecorator{ cdc: cdc, @@ -44,9 +44,9 @@ func (ad CircuitBreakerDecorator) AnteHandle( // Check that the authenticator flow is active if specified, _ := lib.HasSelectedAuthenticatorTxExtensionSpecified(tx, ad.cdc); specified { // Return and call the AnteHandle function on all the authenticator decorators. - return ad.authenticatorAnteHandlerFlow(ctx, tx, simulate) + return ad.authenticatorAnteHandlerFlow.AnteHandle(ctx, tx, simulate, next) } // Return and call the AnteHandle function on all the original decorators. - return ad.originalAnteHandlerFlow(ctx, tx, simulate) + return ad.originalAnteHandlerFlow.AnteHandle(ctx, tx, simulate, next) } diff --git a/protocol/x/accountplus/ante/circuit_breaker_test.go b/protocol/x/accountplus/ante/circuit_breaker_test.go index 08ac7e7a81..b774154142 100644 --- a/protocol/x/accountplus/ante/circuit_breaker_test.go +++ b/protocol/x/accountplus/ante/circuit_breaker_test.go @@ -150,8 +150,8 @@ func (s *AuthenticatorCircuitBreakerAnteSuite) TestCircuitBreakerAnte() { // Create a CircuitBreaker AnteDecorator cbd := ante.NewCircuitBreakerDecorator( s.tApp.App.AppCodec(), - sdk.ChainAnteDecorators(mockTestAuthenticator), - sdk.ChainAnteDecorators(mockTestClassic), + mockTestAuthenticator, + mockTestClassic, ) anteHandler := sdk.ChainAnteDecorators(cbd) diff --git a/protocol/x/accountplus/module.go b/protocol/x/accountplus/module.go index f1e3b6a0ae..41032aef6b 100644 --- a/protocol/x/accountplus/module.go +++ b/protocol/x/accountplus/module.go @@ -61,7 +61,12 @@ func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} // GetTxCmd returns the root Tx command for the module. The subcommands of this root command are used by end-users // to generate new transactions containing messages defined in the module @@ -121,7 +126,8 @@ func (am AppModule) IsOnePerModuleType() {} // RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries func (am AppModule) RegisterServices(cfg module.Configurator) { - // accountplus does not have message and query + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) } // InitGenesis performs the module's genesis initialization. It returns no validator updates. diff --git a/protocol/x/accountplus/types/codec.go b/protocol/x/accountplus/types/codec.go index e3e58daf7d..cbaf4e039b 100644 --- a/protocol/x/accountplus/types/codec.go +++ b/protocol/x/accountplus/types/codec.go @@ -3,6 +3,8 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/types/tx" ) // AuthenticatorTxOptions @@ -13,6 +15,13 @@ type AuthenticatorTxOptions interface { func RegisterCodec(cdc *codec.LegacyAmino) {} func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*tx.TxExtensionOptionI)(nil), &TxExtension{}) + + registry.RegisterImplementations( + (*AuthenticatorTxOptions)(nil), + &TxExtension{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } var ( From ebad2c63c38024e95177ee1e6ae1b3bf6736ed0b Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Mon, 30 Sep 2024 14:38:39 -0400 Subject: [PATCH 056/120] Internalize logic to stage FinalizeBlock events (#2399) --- .../codegen/dydxprotocol/clob/streaming.ts | 16 +- proto/dydxprotocol/clob/streaming.proto | 1 + protocol/mocks/MemClobKeeper.go | 6 +- .../streaming/full_node_streaming_manager.go | 304 ++++++++++-------- protocol/streaming/noop_streaming_manager.go | 21 +- protocol/streaming/types/interface.go | 19 +- protocol/streaming/util/util.go | 8 +- protocol/testutil/memclob/keeper.go | 4 +- protocol/x/clob/keeper/keeper.go | 22 +- protocol/x/clob/keeper/process_operations.go | 16 +- protocol/x/clob/memclob/memclob.go | 2 +- protocol/x/clob/types/mem_clob_keeper.go | 4 +- protocol/x/clob/types/streaming.pb.go | 100 +++++- protocol/x/subaccounts/keeper/subaccount.go | 2 +- 14 files changed, 317 insertions(+), 208 deletions(-) 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 dab8f1e122..1600c2e39c 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts @@ -1,4 +1,4 @@ -import { StreamOrderbookFill, StreamOrderbookFillSDKType } from "./query"; +import { StreamOrderbookFill, StreamOrderbookFillSDKType, StreamOrderbookUpdate, StreamOrderbookUpdateSDKType } from "./query"; import { StreamSubaccountUpdate, StreamSubaccountUpdateSDKType } from "../subaccounts/streaming"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; @@ -7,18 +7,21 @@ import { DeepPartial } from "../../helpers"; export interface StagedFinalizeBlockEvent { orderFill?: StreamOrderbookFill; subaccountUpdate?: StreamSubaccountUpdate; + orderbookUpdate?: StreamOrderbookUpdate; } /** StagedFinalizeBlockEvent is an event staged during `FinalizeBlock`. */ export interface StagedFinalizeBlockEventSDKType { order_fill?: StreamOrderbookFillSDKType; subaccount_update?: StreamSubaccountUpdateSDKType; + orderbook_update?: StreamOrderbookUpdateSDKType; } function createBaseStagedFinalizeBlockEvent(): StagedFinalizeBlockEvent { return { orderFill: undefined, - subaccountUpdate: undefined + subaccountUpdate: undefined, + orderbookUpdate: undefined }; } @@ -32,6 +35,10 @@ export const StagedFinalizeBlockEvent = { StreamSubaccountUpdate.encode(message.subaccountUpdate, writer.uint32(18).fork()).ldelim(); } + if (message.orderbookUpdate !== undefined) { + StreamOrderbookUpdate.encode(message.orderbookUpdate, writer.uint32(26).fork()).ldelim(); + } + return writer; }, @@ -52,6 +59,10 @@ export const StagedFinalizeBlockEvent = { message.subaccountUpdate = StreamSubaccountUpdate.decode(reader, reader.uint32()); break; + case 3: + message.orderbookUpdate = StreamOrderbookUpdate.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -65,6 +76,7 @@ export const StagedFinalizeBlockEvent = { const message = createBaseStagedFinalizeBlockEvent(); 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; return message; } diff --git a/proto/dydxprotocol/clob/streaming.proto b/proto/dydxprotocol/clob/streaming.proto index 06c74ffbe1..ae3811134e 100644 --- a/proto/dydxprotocol/clob/streaming.proto +++ b/proto/dydxprotocol/clob/streaming.proto @@ -12,5 +12,6 @@ message StagedFinalizeBlockEvent { oneof event { StreamOrderbookFill order_fill = 1; dydxprotocol.subaccounts.StreamSubaccountUpdate subaccount_update = 2; + StreamOrderbookUpdate orderbook_update = 3; } } diff --git a/protocol/mocks/MemClobKeeper.go b/protocol/mocks/MemClobKeeper.go index 12a2f8cff3..5d8d68d42f 100644 --- a/protocol/mocks/MemClobKeeper.go +++ b/protocol/mocks/MemClobKeeper.go @@ -415,9 +415,9 @@ func (_m *MemClobKeeper) ReplayPlaceOrder(ctx types.Context, msg *clobtypes.MsgP return r0, r1, r2, r3 } -// SendOrderbookFillUpdates provides a mock function with given fields: ctx, orderbookFills -func (_m *MemClobKeeper) SendOrderbookFillUpdates(ctx types.Context, orderbookFills []clobtypes.StreamOrderbookFill) { - _m.Called(ctx, orderbookFills) +// SendOrderbookFillUpdate provides a mock function with given fields: ctx, orderbookFills +func (_m *MemClobKeeper) SendOrderbookFillUpdate(ctx types.Context, orderbookFill clobtypes.StreamOrderbookFill) { + _m.Called(ctx, orderbookFill) } // SendOrderbookUpdates provides a mock function with given fields: ctx, offchainUpdates diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index c43a254e78..85c265f12e 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -20,6 +20,8 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/streaming/types" streaming_util "github.com/dydxprotocol/v4-chain/protocol/streaming/util" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + + ocutypes "github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates/types" ) var _ types.FullNodeStreamingManager = (*FullNodeStreamingManagerImpl)(nil) @@ -313,10 +315,7 @@ func toOrderbookStreamUpdate( blockHeight uint32, execMode sdk.ExecMode, ) []clobtypes.StreamUpdate { - v1updates, err := streaming_util.GetOffchainUpdatesV1(offchainUpdates) - if err != nil { - panic(err) - } + v1updates := streaming_util.GetOffchainUpdatesV1(offchainUpdates) return []clobtypes.StreamUpdate{ { UpdateMessage: &clobtypes.StreamUpdate_OrderbookUpdate{ @@ -390,39 +389,22 @@ func getStagedEventsCount(store storetypes.KVStore) uint32 { return binary.BigEndian.Uint32(countsBytes) } -// Stage a subaccount update event in transient store, during `FinalizeBlock`. -func (sm *FullNodeStreamingManagerImpl) StageFinalizeBlockSubaccountUpdate( +// Send a subaccount update event. +func (sm *FullNodeStreamingManagerImpl) SendSubaccountUpdate( ctx sdk.Context, subaccountUpdate satypes.StreamSubaccountUpdate, ) { - lib.AssertDeliverTxMode(ctx) - stagedEvent := clobtypes.StagedFinalizeBlockEvent{ - Event: &clobtypes.StagedFinalizeBlockEvent_SubaccountUpdate{ - SubaccountUpdate: &subaccountUpdate, - }, + // If not `DeliverTx`, return since we don't stream optimistic subaccount updates. + if !lib.IsDeliverTxMode(ctx) { + return } - sm.stageFinalizeBlockEvent( - ctx, - sm.cdc.MustMarshal(&stagedEvent), - ) -} -// Stage a fill event in transient store, during `FinalizeBlock`. -// Since `FinalizeBlock` code block can be called more than once with optimistic -// execution (once optimistically and optionally once on the canonical block), -// we need to stage the events in transient store and later emit them -// during `Precommit`. -func (sm *FullNodeStreamingManagerImpl) StageFinalizeBlockFill( - ctx sdk.Context, - fill clobtypes.StreamOrderbookFill, -) { - lib.AssertDeliverTxMode(ctx) + // If `DeliverTx`, updates should be staged to be streamed after consensus finalizes on a block. stagedEvent := clobtypes.StagedFinalizeBlockEvent{ - Event: &clobtypes.StagedFinalizeBlockEvent_OrderFill{ - OrderFill: &fill, + Event: &clobtypes.StagedFinalizeBlockEvent_SubaccountUpdate{ + SubaccountUpdate: &subaccountUpdate, }, } - sm.stageFinalizeBlockEvent( ctx, sm.cdc.MustMarshal(&stagedEvent), @@ -501,29 +483,49 @@ func (sm *FullNodeStreamingManagerImpl) TracksSubaccountId(subaccountId satypes. } func getStreamUpdatesFromOffchainUpdates( - offchainUpdates *clobtypes.OffchainUpdates, + v1updates []ocutypes.OffChainUpdateV1, blockHeight uint32, execMode sdk.ExecMode, ) (streamUpdates []clobtypes.StreamUpdate, clobPairIds []uint32) { // Group updates by clob pair id. - updates := make(map[uint32]*clobtypes.OffchainUpdates) - for _, message := range offchainUpdates.Messages { - clobPairId := message.OrderId.ClobPairId - if _, ok := updates[clobPairId]; !ok { - updates[clobPairId] = clobtypes.NewOffchainUpdates() + clobPairIdToV1Updates := make(map[uint32][]ocutypes.OffChainUpdateV1) + // unique list of clob pair Ids to send updates for. + clobPairIds = make([]uint32, 0) + for _, v1update := range v1updates { + var clobPairId uint32 + switch u := v1update.UpdateMessage.(type) { + case *ocutypes.OffChainUpdateV1_OrderPlace: + clobPairId = u.OrderPlace.Order.OrderId.ClobPairId + case *ocutypes.OffChainUpdateV1_OrderReplace: + clobPairId = u.OrderReplace.OldOrderId.ClobPairId + case *ocutypes.OffChainUpdateV1_OrderRemove: + clobPairId = u.OrderRemove.RemovedOrderId.ClobPairId + case *ocutypes.OffChainUpdateV1_OrderUpdate: + clobPairId = u.OrderUpdate.OrderId.ClobPairId + default: + panic(fmt.Sprintf("Unhandled UpdateMessage type: %v", u)) } - updates[clobPairId].Messages = append(updates[clobPairId].Messages, message) + + if _, ok := clobPairIdToV1Updates[clobPairId]; !ok { + clobPairIdToV1Updates[clobPairId] = []ocutypes.OffChainUpdateV1{} + clobPairIds = append(clobPairIds, clobPairId) + } + clobPairIdToV1Updates[clobPairId] = append(clobPairIdToV1Updates[clobPairId], v1update) } // Unmarshal each per-clob pair message to v1 updates. - streamUpdates = make([]clobtypes.StreamUpdate, 0) - clobPairIds = make([]uint32, 0) - for clobPairId, update := range updates { - v1updates, err := streaming_util.GetOffchainUpdatesV1(update) - if err != nil { - panic(err) + streamUpdates = make([]clobtypes.StreamUpdate, len(clobPairIds)) + + for i, clobPairId := range clobPairIds { + v1updates, exists := clobPairIdToV1Updates[clobPairId] + if !exists { + panic(fmt.Sprintf( + "clob pair id %v not found in clobPairIdToV1Updates: %v", + clobPairId, + clobPairIdToV1Updates, + )) } - streamUpdate := clobtypes.StreamUpdate{ + streamUpdates[i] = clobtypes.StreamUpdate{ UpdateMessage: &clobtypes.StreamUpdate_OrderbookUpdate{ OrderbookUpdate: &clobtypes.StreamOrderbookUpdate{ Updates: v1updates, @@ -533,8 +535,6 @@ func getStreamUpdatesFromOffchainUpdates( BlockHeight: blockHeight, ExecMode: uint32(execMode), } - streamUpdates = append(streamUpdates, streamUpdate) - clobPairIds = append(clobPairIds, clobPairId) } return streamUpdates, clobPairIds @@ -544,18 +544,40 @@ func getStreamUpdatesFromOffchainUpdates( // sends messages to the subscribers. func (sm *FullNodeStreamingManagerImpl) SendOrderbookUpdates( offchainUpdates *clobtypes.OffchainUpdates, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) { - defer metrics.ModuleMeasureSince( - metrics.FullNodeGrpc, - metrics.GrpcSendOrderbookUpdatesLatency, - time.Now(), - ) + v1updates := streaming_util.GetOffchainUpdatesV1(offchainUpdates) + + // If not `DeliverTx`, then updates are optimistic. Stream them directly. + if !lib.IsDeliverTxMode(ctx) { + defer metrics.ModuleMeasureSince( + metrics.FullNodeGrpc, + metrics.GrpcSendOrderbookUpdatesLatency, + time.Now(), + ) - streamUpdates, clobPairIds := getStreamUpdatesFromOffchainUpdates(offchainUpdates, blockHeight, execMode) + streamUpdates, clobPairIds := getStreamUpdatesFromOffchainUpdates( + v1updates, + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), + ctx.ExecMode(), + ) + sm.AddOrderUpdatesToCache(streamUpdates, clobPairIds) + return + } - sm.AddOrderUpdatesToCache(streamUpdates, clobPairIds) + // If `DeliverTx`, updates should be staged to be streamed after consensus finalizes on a block. + stagedEvent := clobtypes.StagedFinalizeBlockEvent{ + Event: &clobtypes.StagedFinalizeBlockEvent_OrderbookUpdate{ + OrderbookUpdate: &clobtypes.StreamOrderbookUpdate{ + Updates: v1updates, + Snapshot: false, + }, + }, + } + sm.stageFinalizeBlockEvent( + ctx, + sm.cdc.MustMarshal(&stagedEvent), + ) } func (sm *FullNodeStreamingManagerImpl) getStreamUpdatesForOrderbookFills( @@ -595,36 +617,52 @@ func (sm *FullNodeStreamingManagerImpl) getStreamUpdatesForOrderbookFills( return streamUpdates, clobPairIds } -// SendOrderbookFillUpdates groups fills by their clob pair ids and +// SendOrderbookFillUpdate groups fills by their clob pair ids and // sends messages to the subscribers. -func (sm *FullNodeStreamingManagerImpl) SendOrderbookFillUpdates( - orderbookFills []clobtypes.StreamOrderbookFill, - blockHeight uint32, - execMode sdk.ExecMode, +func (sm *FullNodeStreamingManagerImpl) SendOrderbookFillUpdate( + orderbookFill clobtypes.StreamOrderbookFill, + ctx sdk.Context, perpetualIdToClobPairId map[uint32][]clobtypes.ClobPairId, ) { - defer metrics.ModuleMeasureSince( - metrics.FullNodeGrpc, - metrics.GrpcSendOrderbookFillsLatency, - time.Now(), - ) + // If not `DeliverTx`, then updates are optimistic. Stream them directly. + if !lib.IsDeliverTxMode(ctx) { + defer metrics.ModuleMeasureSince( + metrics.FullNodeGrpc, + metrics.GrpcSendOrderbookFillsLatency, + time.Now(), + ) - streamUpdates, clobPairIds := sm.getStreamUpdatesForOrderbookFills( - orderbookFills, - blockHeight, - execMode, - perpetualIdToClobPairId, - ) + streamUpdates, clobPairIds := sm.getStreamUpdatesForOrderbookFills( + []clobtypes.StreamOrderbookFill{orderbookFill}, + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), + ctx.ExecMode(), + perpetualIdToClobPairId, + ) + sm.AddOrderUpdatesToCache(streamUpdates, clobPairIds) + return + } + + // If `DeliverTx`, updates should be staged to be streamed after consensus finalizes on a block. + stagedEvent := clobtypes.StagedFinalizeBlockEvent{ + Event: &clobtypes.StagedFinalizeBlockEvent_OrderFill{ + OrderFill: &orderbookFill, + }, + } - sm.AddOrderUpdatesToCache(streamUpdates, clobPairIds) + sm.stageFinalizeBlockEvent( + ctx, + sm.cdc.MustMarshal(&stagedEvent), + ) } // SendTakerOrderStatus sends out a taker order and its status to the full node streaming service. func (sm *FullNodeStreamingManagerImpl) SendTakerOrderStatus( streamTakerOrder clobtypes.StreamTakerOrder, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) { + // In current design, we never send this during `DeliverTx` (`FinalizeBlock`). + lib.AssertCheckTxMode(ctx) + clobPairId := uint32(0) if liqOrder := streamTakerOrder.GetLiquidationOrder(); liqOrder != nil { clobPairId = liqOrder.ClobPairId @@ -639,8 +677,8 @@ func (sm *FullNodeStreamingManagerImpl) SendTakerOrderStatus( UpdateMessage: &clobtypes.StreamUpdate_TakerOrder{ TakerOrder: &streamTakerOrder, }, - BlockHeight: blockHeight, - ExecMode: uint32(execMode), + BlockHeight: lib.MustConvertIntegerToUint32(ctx.BlockHeight()), + ExecMode: uint32(ctx.ExecMode()), }, }, []uint32{clobPairId}, @@ -712,13 +750,7 @@ func (sm *FullNodeStreamingManagerImpl) AddOrderUpdatesToCache( float32(len(updates)), ) - sm.streamUpdateCache = append(sm.streamUpdateCache, updates...) - for _, clobPairId := range clobPairIds { - sm.streamUpdateSubscriptionCache = append( - sm.streamUpdateSubscriptionCache, - sm.clobPairIdToSubscriptionIdMapping[clobPairId], - ) - } + sm.cacheStreamUpdatesByClobPairWithLock(updates, clobPairIds) // Remove all subscriptions and wipe the buffer if buffer overflows. sm.RemoveSubscriptionsAndClearBufferIfFull() @@ -739,13 +771,8 @@ func (sm *FullNodeStreamingManagerImpl) AddSubaccountUpdatesToCache( float32(len(updates)), ) - sm.streamUpdateCache = append(sm.streamUpdateCache, updates...) - for _, subaccountId := range subaccountIds { - sm.streamUpdateSubscriptionCache = append( - sm.streamUpdateSubscriptionCache, - sm.subaccountIdToSubscriptionIdMapping[*subaccountId], - ) - } + sm.cacheStreamUpdatesBySubaccountWithLock(updates, subaccountIds) + sm.RemoveSubscriptionsAndClearBufferIfFull() sm.EmitMetrics() } @@ -850,38 +877,31 @@ func (sm *FullNodeStreamingManagerImpl) GetSubaccountSnapshotsForInitStreams( return ret } -// addBatchUpdatesToCacheWithLock adds batched updates to the cache. -// Used by `StreamBatchUpdatesAfterFinalizeBlock` to batch orderbook, fill -// and subaccount updates in a single stream. -// Note this method requires the lock and assumes that the lock has already been +// 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 // acquired by the caller. -func (sm *FullNodeStreamingManagerImpl) addBatchUpdatesToCacheWithLock( - orderbookStreamUpdates []clobtypes.StreamUpdate, - orderbookClobPairIds []uint32, - fillStreamUpdates []clobtypes.StreamUpdate, - fillClobPairIds []uint32, - subaccountStreamUpdates []clobtypes.StreamUpdate, - subaccountIds []*satypes.SubaccountId, +func (sm *FullNodeStreamingManagerImpl) cacheStreamUpdatesByClobPairWithLock( + streamUpdates []clobtypes.StreamUpdate, + clobPairIds []uint32, ) { - // Add orderbook updates to cache. - sm.streamUpdateCache = append(sm.streamUpdateCache, orderbookStreamUpdates...) - for _, clobPairId := range orderbookClobPairIds { - sm.streamUpdateSubscriptionCache = append( - sm.streamUpdateSubscriptionCache, - sm.clobPairIdToSubscriptionIdMapping[clobPairId], - ) - } - - // Add fill updates to cache. - sm.streamUpdateCache = append(sm.streamUpdateCache, fillStreamUpdates...) - for _, clobPairId := range fillClobPairIds { + sm.streamUpdateCache = append(sm.streamUpdateCache, streamUpdates...) + for _, clobPairId := range clobPairIds { sm.streamUpdateSubscriptionCache = append( sm.streamUpdateSubscriptionCache, sm.clobPairIdToSubscriptionIdMapping[clobPairId], ) } +} - // Add subaccount updates to cache. +// cacheStreamUpdatesBySubaccountWithLock adds subaccount stream updates to cache, +// and store corresponding subaccount Ids. +// This method requires the lock and assumes that the lock has already been +// acquired by the caller. +func (sm *FullNodeStreamingManagerImpl) cacheStreamUpdatesBySubaccountWithLock( + subaccountStreamUpdates []clobtypes.StreamUpdate, + subaccountIds []*satypes.SubaccountId, +) { sm.streamUpdateCache = append(sm.streamUpdateCache, subaccountStreamUpdates...) for _, subaccountId := range subaccountIds { sm.streamUpdateSubscriptionCache = append( @@ -902,41 +922,50 @@ func (sm *FullNodeStreamingManagerImpl) StreamBatchUpdatesAfterFinalizeBlock( // Prevent gas metering from state read. ctx = ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) - finalizedFills, finalizedSubaccountUpdates := sm.getStagedEventsFromFinalizeBlock(ctx) + finalizedFills, + finalizedSubaccountUpdates, + finalizedOrderbookUpdates := sm.getStagedEventsFromFinalizeBlock(ctx) + + sm.Lock() + defer sm.Unlock() + + // Flush all pending updates, since we want the onchain updates to arrive in a batch. + sm.FlushStreamUpdatesWithLock() - orderbookStreamUpdates, orderbookClobPairIds := getStreamUpdatesFromOffchainUpdates( - orderBookUpdatesToSyncLocalOpsQueue, - uint32(ctx.BlockHeight()), + // Cache updates to sync local ops queue + sycnLocalUpdates, syncLocalClobPairIds := getStreamUpdatesFromOffchainUpdates( + streaming_util.GetOffchainUpdatesV1(orderBookUpdatesToSyncLocalOpsQueue), + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), ctx.ExecMode(), ) + sm.cacheStreamUpdatesByClobPairWithLock(sycnLocalUpdates, syncLocalClobPairIds) + // Cache updates for finalized fills. fillStreamUpdates, fillClobPairIds := sm.getStreamUpdatesForOrderbookFills( finalizedFills, - uint32(ctx.BlockHeight()), + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), ctx.ExecMode(), perpetualIdToClobPairId, ) + sm.cacheStreamUpdatesByClobPairWithLock(fillStreamUpdates, fillClobPairIds) + + // Cache updates for finalized orderbook updates (e.g. RemoveOrderFillAmount in `EndBlocker`). + for _, finalizedUpdate := range finalizedOrderbookUpdates { + streamUpdates, clobPairIds := getStreamUpdatesFromOffchainUpdates( + finalizedUpdate.Updates, + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), + ctx.ExecMode(), + ) + sm.cacheStreamUpdatesByClobPairWithLock(streamUpdates, clobPairIds) + } + // Finally, cache updates for finalized subaccount updates subaccountStreamUpdates, subaccountIds := getStreamUpdatesForSubaccountUpdates( finalizedSubaccountUpdates, - uint32(ctx.BlockHeight()), + lib.MustConvertIntegerToUint32(ctx.BlockHeight()), ctx.ExecMode(), ) - - sm.Lock() - defer sm.Unlock() - - // Flush all pending updates, since we want the onchain updates to arrive in a batch. - sm.FlushStreamUpdatesWithLock() - - sm.addBatchUpdatesToCacheWithLock( - orderbookStreamUpdates, - orderbookClobPairIds, - fillStreamUpdates, - fillClobPairIds, - subaccountStreamUpdates, - subaccountIds, - ) + sm.cacheStreamUpdatesBySubaccountWithLock(subaccountStreamUpdates, subaccountIds) // Emit all stream updates in a single batch. // Note we still have the lock, which is released right before function returns. @@ -950,6 +979,7 @@ func (sm *FullNodeStreamingManagerImpl) getStagedEventsFromFinalizeBlock( ) ( finalizedFills []clobtypes.StreamOrderbookFill, finalizedSubaccountUpdates []satypes.StreamSubaccountUpdate, + finalizedOrderbookUpdates []clobtypes.StreamOrderbookUpdate, ) { // Get onchain stream events stored in transient store. stagedEvents := sm.GetStagedFinalizeBlockEvents(ctx) @@ -965,6 +995,10 @@ func (sm *FullNodeStreamingManagerImpl) getStagedEventsFromFinalizeBlock( finalizedFills = append(finalizedFills, *event.OrderFill) case *clobtypes.StagedFinalizeBlockEvent_SubaccountUpdate: finalizedSubaccountUpdates = append(finalizedSubaccountUpdates, *event.SubaccountUpdate) + case *clobtypes.StagedFinalizeBlockEvent_OrderbookUpdate: + finalizedOrderbookUpdates = append(finalizedOrderbookUpdates, *event.OrderbookUpdate) + default: + panic(fmt.Sprintf("Unhandled staged event type: %v\n", stagedEvent.Event)) } } @@ -977,7 +1011,7 @@ func (sm *FullNodeStreamingManagerImpl) getStagedEventsFromFinalizeBlock( float32(len(finalizedFills)), ) - return finalizedFills, finalizedSubaccountUpdates + return finalizedFills, finalizedSubaccountUpdates, finalizedOrderbookUpdates } func (sm *FullNodeStreamingManagerImpl) InitializeNewStreams( diff --git a/protocol/streaming/noop_streaming_manager.go b/protocol/streaming/noop_streaming_manager.go index 4df60bc427..9dc7bf6de9 100644 --- a/protocol/streaming/noop_streaming_manager.go +++ b/protocol/streaming/noop_streaming_manager.go @@ -31,23 +31,20 @@ func (sm *NoopGrpcStreamingManager) Subscribe( func (sm *NoopGrpcStreamingManager) SendOrderbookUpdates( updates *clobtypes.OffchainUpdates, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) { } -func (sm *NoopGrpcStreamingManager) SendOrderbookFillUpdates( - orderbookFills []clobtypes.StreamOrderbookFill, - blockHeight uint32, - execMode sdk.ExecMode, +func (sm *NoopGrpcStreamingManager) SendOrderbookFillUpdate( + orderbookFill clobtypes.StreamOrderbookFill, + ctx sdk.Context, perpetualIdToClobPairId map[uint32][]clobtypes.ClobPairId, ) { } func (sm *NoopGrpcStreamingManager) SendTakerOrderStatus( takerOrder clobtypes.StreamTakerOrder, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) { } @@ -79,19 +76,13 @@ func (sm *NoopGrpcStreamingManager) InitializeNewStreams( func (sm *NoopGrpcStreamingManager) Stop() { } -func (sm *NoopGrpcStreamingManager) StageFinalizeBlockFill( - ctx sdk.Context, - fill clobtypes.StreamOrderbookFill, -) { -} - func (sm *NoopGrpcStreamingManager) GetStagedFinalizeBlockEvents( ctx sdk.Context, ) []clobtypes.StagedFinalizeBlockEvent { return nil } -func (sm *NoopGrpcStreamingManager) StageFinalizeBlockSubaccountUpdate( +func (sm *NoopGrpcStreamingManager) SendSubaccountUpdate( ctx sdk.Context, subaccountUpdate satypes.StreamSubaccountUpdate, ) { diff --git a/protocol/streaming/types/interface.go b/protocol/streaming/types/interface.go index 0f097d3e75..5b42864016 100644 --- a/protocol/streaming/types/interface.go +++ b/protocol/streaming/types/interface.go @@ -31,30 +31,23 @@ type FullNodeStreamingManager interface { ) map[satypes.SubaccountId]*satypes.StreamSubaccountUpdate SendOrderbookUpdates( offchainUpdates *clobtypes.OffchainUpdates, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) - SendOrderbookFillUpdates( - orderbookFills []clobtypes.StreamOrderbookFill, - blockHeight uint32, - execMode sdk.ExecMode, + SendOrderbookFillUpdate( + orderbookFill clobtypes.StreamOrderbookFill, + ctx sdk.Context, perpetualIdToClobPairId map[uint32][]clobtypes.ClobPairId, ) SendTakerOrderStatus( takerOrder clobtypes.StreamTakerOrder, - blockHeight uint32, - execMode sdk.ExecMode, + ctx sdk.Context, ) SendFinalizedSubaccountUpdates( subaccountUpdates []satypes.StreamSubaccountUpdate, blockHeight uint32, execMode sdk.ExecMode, ) - StageFinalizeBlockFill( - ctx sdk.Context, - fill clobtypes.StreamOrderbookFill, - ) - StageFinalizeBlockSubaccountUpdate( + SendSubaccountUpdate( ctx sdk.Context, subaccountUpdate satypes.StreamSubaccountUpdate, ) diff --git a/protocol/streaming/util/util.go b/protocol/streaming/util/util.go index 985a29ef33..bbf37e3340 100644 --- a/protocol/streaming/util/util.go +++ b/protocol/streaming/util/util.go @@ -1,21 +1,23 @@ package util import ( + "fmt" + "github.com/cosmos/gogoproto/proto" ocutypes "github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ) // GetOffchainUpdatesV1 unmarshals messages in offchain updates to OffchainUpdateV1. -func GetOffchainUpdatesV1(offchainUpdates *clobtypes.OffchainUpdates) ([]ocutypes.OffChainUpdateV1, error) { +func GetOffchainUpdatesV1(offchainUpdates *clobtypes.OffchainUpdates) []ocutypes.OffChainUpdateV1 { v1updates := make([]ocutypes.OffChainUpdateV1, 0) for _, message := range offchainUpdates.Messages { var update ocutypes.OffChainUpdateV1 err := proto.Unmarshal(message.Message.Value, &update) if err != nil { - return nil, err + panic(fmt.Sprintf("Failed to get OffchainUpdatesV1: %v", err)) } v1updates = append(v1updates, update) } - return v1updates, nil + return v1updates } diff --git a/protocol/testutil/memclob/keeper.go b/protocol/testutil/memclob/keeper.go index 22ba76acdd..376f6fb30a 100644 --- a/protocol/testutil/memclob/keeper.go +++ b/protocol/testutil/memclob/keeper.go @@ -508,9 +508,9 @@ func (f *FakeMemClobKeeper) SendOrderbookUpdates( ) { } -func (f *FakeMemClobKeeper) SendOrderbookFillUpdates( +func (f *FakeMemClobKeeper) SendOrderbookFillUpdate( ctx sdk.Context, - orderbookFills []types.StreamOrderbookFill, + orderbookFill types.StreamOrderbookFill, ) { } diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index 8c39342ca6..f49eb61271 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -309,23 +309,18 @@ func (k Keeper) SendOrderbookUpdates( k.GetFullNodeStreamingManager().SendOrderbookUpdates( offchainUpdates, - lib.MustConvertIntegerToUint32(ctx.BlockHeight()), - ctx.ExecMode(), + ctx, ) } -// SendOrderbookFillUpdates sends the orderbook fills to the Full Node streaming manager. -func (k Keeper) SendOrderbookFillUpdates( +// SendOrderbookFillUpdate sends the orderbook fills to the Full Node streaming manager. +func (k Keeper) SendOrderbookFillUpdate( ctx sdk.Context, - orderbookFills []types.StreamOrderbookFill, + orderbookFill types.StreamOrderbookFill, ) { - if len(orderbookFills) == 0 { - return - } - k.GetFullNodeStreamingManager().SendOrderbookFillUpdates( - orderbookFills, - lib.MustConvertIntegerToUint32(ctx.BlockHeight()), - ctx.ExecMode(), + k.GetFullNodeStreamingManager().SendOrderbookFillUpdate( + orderbookFill, + ctx, k.PerpetualIdToClobPairId, ) } @@ -337,7 +332,6 @@ func (k Keeper) SendTakerOrderStatus( ) { k.GetFullNodeStreamingManager().SendTakerOrderStatus( takerOrder, - lib.MustConvertIntegerToUint32(ctx.BlockHeight()), - ctx.ExecMode(), + ctx, ) } diff --git a/protocol/x/clob/keeper/process_operations.go b/protocol/x/clob/keeper/process_operations.go index 026d9d316c..86808afb5d 100644 --- a/protocol/x/clob/keeper/process_operations.go +++ b/protocol/x/clob/keeper/process_operations.go @@ -560,9 +560,10 @@ func (k Keeper) PersistMatchOrdersToState( makerOrders, ) - k.GetFullNodeStreamingManager().StageFinalizeBlockFill( - ctx, + k.GetFullNodeStreamingManager().SendOrderbookFillUpdate( streamOrderbookFill, + ctx, + k.PerpetualIdToClobPairId, ) } @@ -670,9 +671,10 @@ func (k Keeper) PersistMatchLiquidationToState( takerOrder, makerOrders, ) - k.GetFullNodeStreamingManager().StageFinalizeBlockFill( - ctx, + k.GetFullNodeStreamingManager().SendOrderbookFillUpdate( streamOrderbookFill, + ctx, + k.PerpetualIdToClobPairId, ) } return nil @@ -843,11 +845,9 @@ func (k Keeper) PersistMatchDeleveragingToState( }, }, } - k.SendOrderbookFillUpdates( + k.SendOrderbookFillUpdate( ctx, - []types.StreamOrderbookFill{ - streamOrderbookFill, - }, + streamOrderbookFill, ) } } diff --git a/protocol/x/clob/memclob/memclob.go b/protocol/x/clob/memclob/memclob.go index d6d1e08774..db541650c3 100644 --- a/protocol/x/clob/memclob/memclob.go +++ b/protocol/x/clob/memclob/memclob.go @@ -402,7 +402,7 @@ func (m *MemClobPriceTimePriority) mustUpdateMemclobStateWithMatches( ) clobMatch := internalOperation.GetMatch() orderbookMatchFill := m.GenerateStreamOrderbookFill(ctx, *clobMatch, takerOrder, makerOrders) - m.clobKeeper.SendOrderbookFillUpdates(ctx, []types.StreamOrderbookFill{orderbookMatchFill}) + m.clobKeeper.SendOrderbookFillUpdate(ctx, orderbookMatchFill) } // Build a slice of all subaccounts which had matches this matching loop, and sort them for determinism. diff --git a/protocol/x/clob/types/mem_clob_keeper.go b/protocol/x/clob/types/mem_clob_keeper.go index d555367718..6e25cadf35 100644 --- a/protocol/x/clob/types/mem_clob_keeper.go +++ b/protocol/x/clob/types/mem_clob_keeper.go @@ -102,9 +102,9 @@ type MemClobKeeper interface { ctx sdk.Context, offchainUpdates *OffchainUpdates, ) - SendOrderbookFillUpdates( + SendOrderbookFillUpdate( ctx sdk.Context, - orderbookFills []StreamOrderbookFill, + orderbookFill StreamOrderbookFill, ) SendTakerOrderStatus( ctx sdk.Context, diff --git a/protocol/x/clob/types/streaming.pb.go b/protocol/x/clob/types/streaming.pb.go index 83b8db719a..1f6f552fb3 100644 --- a/protocol/x/clob/types/streaming.pb.go +++ b/protocol/x/clob/types/streaming.pb.go @@ -30,6 +30,7 @@ type StagedFinalizeBlockEvent struct { // Types that are valid to be assigned to Event: // *StagedFinalizeBlockEvent_OrderFill // *StagedFinalizeBlockEvent_SubaccountUpdate + // *StagedFinalizeBlockEvent_OrderbookUpdate Event isStagedFinalizeBlockEvent_Event `protobuf_oneof:"event"` } @@ -78,9 +79,13 @@ type StagedFinalizeBlockEvent_OrderFill struct { type StagedFinalizeBlockEvent_SubaccountUpdate struct { SubaccountUpdate *types.StreamSubaccountUpdate `protobuf:"bytes,2,opt,name=subaccount_update,json=subaccountUpdate,proto3,oneof" json:"subaccount_update,omitempty"` } +type StagedFinalizeBlockEvent_OrderbookUpdate struct { + OrderbookUpdate *StreamOrderbookUpdate `protobuf:"bytes,3,opt,name=orderbook_update,json=orderbookUpdate,proto3,oneof" json:"orderbook_update,omitempty"` +} func (*StagedFinalizeBlockEvent_OrderFill) isStagedFinalizeBlockEvent_Event() {} func (*StagedFinalizeBlockEvent_SubaccountUpdate) isStagedFinalizeBlockEvent_Event() {} +func (*StagedFinalizeBlockEvent_OrderbookUpdate) isStagedFinalizeBlockEvent_Event() {} func (m *StagedFinalizeBlockEvent) GetEvent() isStagedFinalizeBlockEvent_Event { if m != nil { @@ -103,11 +108,19 @@ func (m *StagedFinalizeBlockEvent) GetSubaccountUpdate() *types.StreamSubaccount return nil } +func (m *StagedFinalizeBlockEvent) GetOrderbookUpdate() *StreamOrderbookUpdate { + if x, ok := m.GetEvent().(*StagedFinalizeBlockEvent_OrderbookUpdate); ok { + return x.OrderbookUpdate + } + 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), } } @@ -118,25 +131,26 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/streaming.proto", fileDescriptor_cecf6ffcf2554dee) } var fileDescriptor_cecf6ffcf2554dee = []byte{ - // 281 bytes of a gzipped FileDescriptorProto + // 303 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, 0x59, - 0x46, 0x2e, 0x89, 0xe0, 0x92, 0xc4, 0xf4, 0xd4, 0x14, 0xb7, 0xcc, 0xbc, 0xc4, 0x9c, 0xcc, 0xaa, + 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, 0x9c, 0xd8, 0xb9, 0x58, 0x53, 0x41, 0x4e, 0x76, 0x0a, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, - 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, - 0xc6, 0x63, 0x39, 0x86, 0x28, 0xb3, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, - 0x7d, 0x94, 0x30, 0x29, 0x33, 0xd1, 0x4d, 0xce, 0x48, 0xcc, 0xcc, 0xd3, 0x87, 0x8b, 0x54, 0x40, - 0xc2, 0xa9, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x2c, 0x6c, 0x0c, 0x08, 0x00, 0x00, 0xff, - 0xff, 0x65, 0x71, 0xd8, 0xa8, 0xa9, 0x01, 0x00, 0x00, + 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, } func (m *StagedFinalizeBlockEvent) Marshal() (dAtA []byte, err error) { @@ -213,6 +227,27 @@ func (m *StagedFinalizeBlockEvent_SubaccountUpdate) MarshalToSizedBuffer(dAtA [] } return len(dAtA) - i, nil } +func (m *StagedFinalizeBlockEvent_OrderbookUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StagedFinalizeBlockEvent_OrderbookUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.OrderbookUpdate != nil { + { + size, err := m.OrderbookUpdate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStreaming(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} func encodeVarintStreaming(dAtA []byte, offset int, v uint64) int { offset -= sovStreaming(v) base := offset @@ -260,6 +295,18 @@ func (m *StagedFinalizeBlockEvent_SubaccountUpdate) Size() (n int) { } return n } +func (m *StagedFinalizeBlockEvent_OrderbookUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.OrderbookUpdate != nil { + l = m.OrderbookUpdate.Size() + n += 1 + l + sovStreaming(uint64(l)) + } + return n +} func sovStreaming(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 @@ -366,6 +413,41 @@ func (m *StagedFinalizeBlockEvent) Unmarshal(dAtA []byte) error { } m.Event = &StagedFinalizeBlockEvent_SubaccountUpdate{v} iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OrderbookUpdate", 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 := &StreamOrderbookUpdate{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Event = &StagedFinalizeBlockEvent_OrderbookUpdate{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStreaming(dAtA[iNdEx:]) diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index 5eb650cce0..e72ccd60e7 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -445,7 +445,7 @@ func (k Keeper) UpdateSubaccounts( if lib.IsDeliverTxMode(ctx) && k.GetFullNodeStreamingManager().Enabled() { if k.GetFullNodeStreamingManager().TracksSubaccountId(*u.SettledSubaccount.Id) { subaccountUpdate := GenerateStreamSubaccountUpdate(u, fundingPayments) - k.GetFullNodeStreamingManager().StageFinalizeBlockSubaccountUpdate( + k.GetFullNodeStreamingManager().SendSubaccountUpdate( ctx, subaccountUpdate, ) From b7dc45651b1f3828073b74a57c95b29b2e6404f3 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:30:39 -0400 Subject: [PATCH 057/120] [CT-1258] add order removal reason for expired permissioned keys (#2407) --- .../dydxprotocol/clob/order_removals.ts | 19 +++++ proto/dydxprotocol/clob/order_removals.proto | 3 + .../indexer/shared/order_removal_reason.go | 4 ++ protocol/x/clob/types/order_removals.pb.go | 69 ++++++++++--------- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/order_removals.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/order_removals.ts index dc69050f2c..378e69347f 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/order_removals.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/order_removals.ts @@ -65,6 +65,12 @@ export enum OrderRemoval_RemovalReason { * would lead to the subaccount violating isolated subaccount constraints. */ REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS = 8, + + /** + * REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED - REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED represents a removal of an order + * that was placed using an expired permissioned key. + */ + REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED = 9, UNRECOGNIZED = -1, } export enum OrderRemoval_RemovalReasonSDKType { @@ -131,6 +137,12 @@ export enum OrderRemoval_RemovalReasonSDKType { * would lead to the subaccount violating isolated subaccount constraints. */ REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS = 8, + + /** + * REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED - REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED represents a removal of an order + * that was placed using an expired permissioned key. + */ + REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED = 9, UNRECOGNIZED = -1, } export function orderRemoval_RemovalReasonFromJSON(object: any): OrderRemoval_RemovalReason { @@ -171,6 +183,10 @@ export function orderRemoval_RemovalReasonFromJSON(object: any): OrderRemoval_Re case "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS": return OrderRemoval_RemovalReason.REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS; + case 9: + case "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED": + return OrderRemoval_RemovalReason.REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED; + case -1: case "UNRECOGNIZED": default: @@ -206,6 +222,9 @@ export function orderRemoval_RemovalReasonToJSON(object: OrderRemoval_RemovalRea case OrderRemoval_RemovalReason.REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS: return "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS"; + case OrderRemoval_RemovalReason.REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED: + return "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED"; + case OrderRemoval_RemovalReason.UNRECOGNIZED: default: return "UNRECOGNIZED"; diff --git a/proto/dydxprotocol/clob/order_removals.proto b/proto/dydxprotocol/clob/order_removals.proto index 5c6d45a990..930fc51142 100644 --- a/proto/dydxprotocol/clob/order_removals.proto +++ b/proto/dydxprotocol/clob/order_removals.proto @@ -48,6 +48,9 @@ message OrderRemoval { // REMOVAL_REASON_FULLY_FILLED represents a removal of an order that // would lead to the subaccount violating isolated subaccount constraints. REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS = 8; + // REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED represents a removal of an order + // that was placed using an expired permissioned key. + REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED = 9; } RemovalReason removal_reason = 2; diff --git a/protocol/indexer/shared/order_removal_reason.go b/protocol/indexer/shared/order_removal_reason.go index 866b527160..639b0cc161 100644 --- a/protocol/indexer/shared/order_removal_reason.go +++ b/protocol/indexer/shared/order_removal_reason.go @@ -30,6 +30,10 @@ func ConvertOrderRemovalReasonToIndexerOrderRemovalReason( reason = sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_IMMEDIATE_OR_CANCEL_WOULD_REST_ON_BOOK case clobtypes.OrderRemoval_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS: reason = sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS + case clobtypes.OrderRemoval_REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED: + // This is a special case where the order is no longer valid because the permissioned key used to placed + // the order has expired. + reason = sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_EXPIRED default: panic("ConvertOrderRemovalReasonToIndexerOrderRemovalReason: unspecified removal reason not allowed") } diff --git a/protocol/x/clob/types/order_removals.pb.go b/protocol/x/clob/types/order_removals.pb.go index d333b7750e..f1fc168ead 100644 --- a/protocol/x/clob/types/order_removals.pb.go +++ b/protocol/x/clob/types/order_removals.pb.go @@ -63,6 +63,9 @@ const ( // REMOVAL_REASON_FULLY_FILLED represents a removal of an order that // would lead to the subaccount violating isolated subaccount constraints. OrderRemoval_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS OrderRemoval_RemovalReason = 8 + // REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED represents a removal of an order + // that was placed using an expired permissioned key. + OrderRemoval_REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED OrderRemoval_RemovalReason = 9 ) var OrderRemoval_RemovalReason_name = map[int32]string{ @@ -75,6 +78,7 @@ var OrderRemoval_RemovalReason_name = map[int32]string{ 6: "REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK", 7: "REMOVAL_REASON_FULLY_FILLED", 8: "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS", + 9: "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED", } var OrderRemoval_RemovalReason_value = map[string]int32{ @@ -87,6 +91,7 @@ var OrderRemoval_RemovalReason_value = map[string]int32{ "REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK": 6, "REMOVAL_REASON_FULLY_FILLED": 7, "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS": 8, + "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED": 9, } func (x OrderRemoval_RemovalReason) String() string { @@ -160,37 +165,39 @@ func init() { } var fileDescriptor_60fa12f781955c9f = []byte{ - // 479 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x4e, 0xdb, 0x4c, - 0x14, 0xc5, 0x63, 0xc8, 0x07, 0x68, 0xbe, 0x82, 0xdc, 0x51, 0x17, 0x28, 0x55, 0x0d, 0x8d, 0x54, - 0xc4, 0x06, 0xbb, 0xa5, 0xf4, 0x8f, 0x44, 0x37, 0x63, 0xcf, 0x58, 0x1a, 0x65, 0xf0, 0x44, 0x33, - 0x76, 0x2a, 0xd8, 0x5c, 0x25, 0x71, 0x14, 0x22, 0x05, 0x06, 0x39, 0x29, 0x82, 0xb7, 0xe8, 0x9b, - 0xf4, 0x35, 0x58, 0x22, 0x75, 0xd3, 0x55, 0x55, 0x25, 0x2f, 0x52, 0xd9, 0x8e, 0x2a, 0x12, 0x9a, - 0xae, 0x3c, 0xf7, 0xde, 0xdf, 0x39, 0xe7, 0xca, 0xba, 0x68, 0x2f, 0xbd, 0x4d, 0x6f, 0xae, 0x32, - 0x33, 0x36, 0x5d, 0x33, 0xf4, 0xba, 0x43, 0xd3, 0xf1, 0x4c, 0x96, 0xf6, 0x32, 0xc8, 0x7a, 0x17, - 0xe6, 0xba, 0x3d, 0x1c, 0xb9, 0xc5, 0x10, 0x3f, 0x7d, 0xc8, 0xb9, 0x39, 0x57, 0x7b, 0xd6, 0x37, - 0x7d, 0x53, 0xb4, 0xbc, 0xfc, 0x55, 0x82, 0xb5, 0x17, 0x4b, 0x0c, 0xcb, 0x71, 0xfd, 0x7b, 0x15, - 0x3d, 0x91, 0x79, 0xad, 0x4a, 0x7f, 0x7c, 0x8c, 0x36, 0xca, 0xc0, 0x41, 0xba, 0x6d, 0xed, 0x5a, - 0xfb, 0xff, 0x1f, 0xd6, 0xdc, 0x47, 0x59, 0x6e, 0x21, 0xe1, 0xa9, 0x5f, 0xbd, 0xfb, 0xb9, 0x53, - 0x51, 0xeb, 0xa6, 0x2c, 0x71, 0x8c, 0xb6, 0x66, 0x7b, 0x42, 0xd6, 0x6b, 0x8f, 0xcc, 0xe5, 0xf6, - 0xca, 0xae, 0xb5, 0xbf, 0x75, 0x78, 0xb0, 0xcc, 0x62, 0x96, 0xea, 0xce, 0xbe, 0xaa, 0x10, 0xa9, - 0xcd, 0xec, 0x61, 0x59, 0xff, 0xb6, 0x8a, 0x36, 0xe7, 0x00, 0xec, 0xa0, 0x9a, 0x62, 0x27, 0xb2, - 0x45, 0x04, 0x28, 0x46, 0xb4, 0x8c, 0x20, 0x89, 0x74, 0x93, 0x05, 0x3c, 0xe4, 0x8c, 0xda, 0x15, - 0xbc, 0x87, 0xea, 0x8f, 0xe6, 0x94, 0xa9, 0x40, 0x0a, 0x41, 0x62, 0xa6, 0x88, 0xe0, 0x67, 0x8c, - 0xda, 0xd6, 0x5f, 0x38, 0x1e, 0xb5, 0x88, 0xe0, 0x14, 0x14, 0xa3, 0x49, 0xc0, 0x40, 0x46, 0xe2, - 0xd4, 0x5e, 0xc1, 0x47, 0xe8, 0xf5, 0x02, 0xd7, 0x94, 0x3a, 0x2e, 0xa6, 0xf0, 0x59, 0x26, 0x82, - 0x42, 0xa0, 0xa4, 0xd6, 0x70, 0x42, 0x1a, 0x4c, 0x81, 0x54, 0x94, 0x29, 0x7b, 0x15, 0xbf, 0x42, - 0x2f, 0x97, 0xb8, 0x6b, 0x26, 0x42, 0x88, 0x15, 0xa1, 0xcc, 0xae, 0xe2, 0x4f, 0xe8, 0xe3, 0x02, - 0x16, 0xc8, 0x88, 0xf2, 0x98, 0xcb, 0x88, 0x08, 0x08, 0x65, 0x03, 0x82, 0x22, 0x22, 0x92, 0x31, - 0xf8, 0x0c, 0xc2, 0x44, 0x88, 0x53, 0x08, 0xb9, 0x10, 0x8c, 0xda, 0xff, 0xe1, 0x77, 0xe8, 0xcd, - 0x3f, 0xd4, 0x5c, 0x06, 0xb3, 0x05, 0x15, 0x2b, 0x16, 0x06, 0x5f, 0xca, 0x86, 0xbd, 0x86, 0x77, - 0xd0, 0xf3, 0x05, 0xd9, 0x9c, 0xef, 0x3a, 0x3e, 0x46, 0x1f, 0x16, 0x80, 0x16, 0x97, 0xf9, 0xdf, - 0xd3, 0xc0, 0x75, 0xf1, 0xa0, 0xa0, 0x13, 0x9f, 0x04, 0x81, 0x4c, 0xa2, 0x38, 0x0f, 0xd5, 0xb1, - 0x22, 0x3c, 0x8a, 0xb5, 0xbd, 0xe1, 0x37, 0xef, 0x26, 0x8e, 0x75, 0x3f, 0x71, 0xac, 0x5f, 0x13, - 0xc7, 0xfa, 0x3a, 0x75, 0x2a, 0xf7, 0x53, 0xa7, 0xf2, 0x63, 0xea, 0x54, 0xce, 0xde, 0xf7, 0x07, - 0xe3, 0xf3, 0x2f, 0x1d, 0xb7, 0x6b, 0x2e, 0xbc, 0xb9, 0xcb, 0xbc, 0x3e, 0x3a, 0xe8, 0x9e, 0xb7, - 0x07, 0x97, 0xde, 0x9f, 0xce, 0x4d, 0x79, 0xad, 0xe3, 0xdb, 0xab, 0xde, 0xa8, 0xb3, 0x56, 0xb4, - 0xdf, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x45, 0x84, 0x1d, 0xbf, 0x20, 0x03, 0x00, 0x00, + // 500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x5d, 0x6b, 0x13, 0x41, + 0x14, 0x86, 0xb3, 0xfd, 0x76, 0xb4, 0x65, 0x1d, 0xbc, 0x28, 0x11, 0xb7, 0x35, 0x60, 0x2d, 0x48, + 0x37, 0x5a, 0xeb, 0x07, 0xd4, 0x9b, 0xcd, 0xce, 0x09, 0x0c, 0x99, 0xec, 0x84, 0x99, 0xdd, 0x68, + 0x7a, 0x73, 0xc8, 0x17, 0x69, 0x20, 0xed, 0x94, 0x4d, 0x2c, 0xed, 0x9d, 0x3f, 0xc1, 0x9f, 0xd5, + 0xcb, 0x5e, 0x7a, 0x21, 0x22, 0xc9, 0x1f, 0x91, 0xec, 0x06, 0x69, 0xb6, 0xc6, 0xab, 0x99, 0x73, + 0xce, 0xf3, 0xbe, 0xef, 0x61, 0x18, 0xb2, 0xd7, 0xb9, 0xee, 0x5c, 0x5d, 0xc4, 0x66, 0x64, 0xda, + 0x66, 0x50, 0x6c, 0x0f, 0x4c, 0xab, 0x68, 0xe2, 0x4e, 0x37, 0xc6, 0xb8, 0x7b, 0x66, 0x2e, 0x9b, + 0x83, 0xa1, 0x9b, 0x0c, 0xe9, 0xe3, 0xbb, 0x9c, 0x3b, 0xe5, 0xf2, 0x4f, 0x7a, 0xa6, 0x67, 0x92, + 0x56, 0x71, 0x7a, 0x4b, 0xc1, 0xfc, 0xb3, 0x05, 0x86, 0xe9, 0xb8, 0xf0, 0x6d, 0x95, 0x3c, 0x92, + 0xd3, 0x5a, 0xa5, 0xfe, 0xf4, 0x98, 0x6c, 0xa4, 0x81, 0xfd, 0xce, 0xb6, 0xb5, 0x6b, 0xed, 0x3f, + 0x3c, 0xcc, 0xbb, 0xf7, 0xb2, 0xdc, 0x44, 0xc2, 0x3b, 0xa5, 0x95, 0x9b, 0x5f, 0x3b, 0x39, 0xb5, + 0x6e, 0xd2, 0x92, 0x86, 0x64, 0x6b, 0xb6, 0x27, 0xc6, 0xdd, 0xe6, 0xd0, 0x9c, 0x6f, 0x2f, 0xed, + 0x5a, 0xfb, 0x5b, 0x87, 0x07, 0x8b, 0x2c, 0x66, 0xa9, 0xee, 0xec, 0x54, 0x89, 0x48, 0x6d, 0xc6, + 0x77, 0xcb, 0xc2, 0xcf, 0x65, 0xb2, 0x39, 0x07, 0x50, 0x87, 0xe4, 0x15, 0x54, 0x65, 0xdd, 0x13, + 0xa8, 0xc0, 0xd3, 0x32, 0xc0, 0x28, 0xd0, 0x35, 0xf0, 0x79, 0x99, 0x03, 0xb3, 0x73, 0x74, 0x8f, + 0x14, 0xee, 0xcd, 0x19, 0x28, 0x5f, 0x0a, 0xe1, 0x85, 0xa0, 0x3c, 0xc1, 0x4f, 0x80, 0xd9, 0xd6, + 0x3f, 0x38, 0x1e, 0xd4, 0x3d, 0xc1, 0x19, 0x2a, 0x60, 0x91, 0x0f, 0x28, 0x03, 0xd1, 0xb0, 0x97, + 0xe8, 0x11, 0x79, 0x9d, 0xe1, 0x6a, 0x52, 0x87, 0xc9, 0x14, 0x3f, 0xcb, 0x48, 0x30, 0xf4, 0x95, + 0xd4, 0x1a, 0xab, 0x5e, 0x05, 0x14, 0x4a, 0xc5, 0x40, 0xd9, 0xcb, 0xf4, 0x05, 0x79, 0xbe, 0xc0, + 0x5d, 0x83, 0x28, 0x63, 0xa8, 0x3c, 0x06, 0xf6, 0x0a, 0xfd, 0x44, 0x3e, 0x66, 0x30, 0x5f, 0x06, + 0x8c, 0x87, 0x5c, 0x06, 0x9e, 0xc0, 0xb2, 0xac, 0xa0, 0x9f, 0x44, 0x04, 0x32, 0xc4, 0x12, 0x60, + 0x39, 0x12, 0xa2, 0x81, 0x65, 0x2e, 0x04, 0x30, 0x7b, 0x95, 0xbe, 0x23, 0x6f, 0xfe, 0xa3, 0xe6, + 0xd2, 0x9f, 0x2d, 0xa8, 0x20, 0x59, 0x18, 0x4b, 0x52, 0x56, 0xec, 0x35, 0xba, 0x43, 0x9e, 0x66, + 0x64, 0x73, 0xbe, 0xeb, 0xf4, 0x98, 0x7c, 0xc8, 0x00, 0x75, 0x2e, 0xa7, 0xaf, 0xa7, 0x91, 0xeb, + 0xe4, 0xc2, 0x50, 0x47, 0x25, 0xcf, 0xf7, 0x65, 0x14, 0x84, 0xd3, 0x50, 0x1d, 0x2a, 0x8f, 0x07, + 0xa1, 0xb6, 0x37, 0xe8, 0x2b, 0xf2, 0x32, 0xfb, 0x5e, 0xa0, 0xaa, 0x5c, 0x6b, 0x2e, 0x03, 0x60, + 0x58, 0x81, 0x06, 0xc2, 0x97, 0x1a, 0x57, 0xc0, 0xec, 0x07, 0xa5, 0xda, 0xcd, 0xd8, 0xb1, 0x6e, + 0xc7, 0x8e, 0xf5, 0x7b, 0xec, 0x58, 0xdf, 0x27, 0x4e, 0xee, 0x76, 0xe2, 0xe4, 0x7e, 0x4c, 0x9c, + 0xdc, 0xc9, 0xfb, 0x5e, 0x7f, 0x74, 0xfa, 0xb5, 0xe5, 0xb6, 0xcd, 0x59, 0x71, 0xee, 0x1b, 0x5f, + 0x1e, 0x1d, 0xb4, 0x4f, 0x9b, 0xfd, 0xf3, 0xe2, 0xdf, 0xce, 0x55, 0xfa, 0xb5, 0x47, 0xd7, 0x17, + 0xdd, 0x61, 0x6b, 0x2d, 0x69, 0xbf, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xba, 0xd3, 0xd2, 0xeb, + 0x4d, 0x03, 0x00, 0x00, } func (m *OrderRemoval) Marshal() (dAtA []byte, err error) { From 00af8a073c743f7abb2f6712a258a50913ed68bd Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:17:44 -0400 Subject: [PATCH 058/120] [CT-1259] account plus module code cleanup (#2408) --- protocol/app/app.go | 2 +- protocol/x/accountplus/ante/ante.go | 3 +- .../x/accountplus/authenticator/all_of.go | 17 ++-- .../x/accountplus/authenticator/any_of.go | 17 ++-- .../authenticator/clob_pair_id_filter.go | 11 +-- .../authenticator/clob_pair_id_filter_test.go | 3 +- .../x/accountplus/authenticator/composite.go | 5 +- .../authenticator/composition_test.go | 79 ++++++++++--------- .../x/accountplus/authenticator/manager.go | 24 +++--- .../accountplus/authenticator/manager_test.go | 29 +++---- .../authenticator/message_filter.go | 11 +-- .../authenticator/message_filter_test.go | 3 +- .../authenticator/signature_authenticator.go | 11 +-- .../signature_authenticator_test.go | 5 +- .../authenticator/subaccount_filter.go | 11 +-- .../authenticator/subaccount_filter_test.go | 3 +- .../x/accountplus/keeper/authenticators.go | 13 ++- protocol/x/accountplus/keeper/keeper_test.go | 2 +- .../authentication_request.go | 59 ++++---------- .../testutils/generic_authenticator.go | 12 +-- .../testutils/spy_authenticator.go | 12 +-- .../{authenticator => types}/iface.go | 2 +- .../{authenticator => types}/requests.go | 28 ++++++- 23 files changed, 189 insertions(+), 173 deletions(-) rename protocol/x/accountplus/{authenticator => lib}/authentication_request.go (77%) rename protocol/x/accountplus/{authenticator => types}/iface.go (99%) rename protocol/x/accountplus/{authenticator => types}/requests.go (69%) diff --git a/protocol/app/app.go b/protocol/app/app.go index f3cbff3f6b..08b46bc042 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1232,7 +1232,7 @@ func New( // Initialize authenticators app.AuthenticatorManager = authenticator.NewAuthenticatorManager() - app.AuthenticatorManager.InitializeAuthenticators([]authenticator.Authenticator{ + app.AuthenticatorManager.InitializeAuthenticators([]accountplusmoduletypes.Authenticator{ authenticator.NewSignatureVerification(app.AccountKeeper), }) app.AccountPlusKeeper = *accountplusmodulekeeper.NewKeeper( diff --git a/protocol/x/accountplus/ante/ante.go b/protocol/x/accountplus/ante/ante.go index c68c53d277..e83e20b430 100644 --- a/protocol/x/accountplus/ante/ante.go +++ b/protocol/x/accountplus/ante/ante.go @@ -15,7 +15,6 @@ import ( txsigning "cosmossdk.io/x/tx/signing" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" - "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" @@ -133,7 +132,7 @@ func (ad AuthenticatorDecorator) AnteHandle( } // Generate the authentication request data - authenticationRequest, err := authenticator.GenerateAuthenticationRequest( + authenticationRequest, err := lib.GenerateAuthenticationRequest( ctx, ad.cdc, ad.accountKeeper, diff --git a/protocol/x/accountplus/authenticator/all_of.go b/protocol/x/accountplus/authenticator/all_of.go index 5a766dbf7a..34460098cc 100644 --- a/protocol/x/accountplus/authenticator/all_of.go +++ b/protocol/x/accountplus/authenticator/all_of.go @@ -6,20 +6,21 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) type AllOf struct { - SubAuthenticators []Authenticator + SubAuthenticators []types.Authenticator am *AuthenticatorManager signatureAssignment SignatureAssignment } -var _ Authenticator = &AllOf{} +var _ types.Authenticator = &AllOf{} func NewAllOf(am *AuthenticatorManager) AllOf { return AllOf{ am: am, - SubAuthenticators: []Authenticator{}, + SubAuthenticators: []types.Authenticator{}, signatureAssignment: Single, } } @@ -27,7 +28,7 @@ func NewAllOf(am *AuthenticatorManager) AllOf { func NewPartitionedAllOf(am *AuthenticatorManager) AllOf { return AllOf{ am: am, - SubAuthenticators: []Authenticator{}, + SubAuthenticators: []types.Authenticator{}, signatureAssignment: Partitioned, } } @@ -47,7 +48,7 @@ func (aoa AllOf) StaticGas() uint64 { return totalGas } -func (aoa AllOf) Initialize(config []byte) (Authenticator, error) { +func (aoa AllOf) Initialize(config []byte) (types.Authenticator, error) { var initDatas []SubAuthenticatorInitData if err := json.Unmarshal(config, &initDatas); err != nil { return nil, errorsmod.Wrap(err, "failed to parse sub-authenticators initialization data") @@ -74,7 +75,7 @@ func (aoa AllOf) Initialize(config []byte) (Authenticator, error) { return aoa, nil } -func (aoa AllOf) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AllOf) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if len(aoa.SubAuthenticators) == 0 { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "no sub-authenticators provided") } @@ -104,11 +105,11 @@ func (aoa AllOf) Authenticate(ctx sdk.Context, request AuthenticationRequest) er return nil } -func (aoa AllOf) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AllOf) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return subTrack(ctx, request, aoa.SubAuthenticators) } -func (aoa AllOf) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AllOf) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { var signatures [][]byte var err error if aoa.signatureAssignment == Partitioned { diff --git a/protocol/x/accountplus/authenticator/any_of.go b/protocol/x/accountplus/authenticator/any_of.go index 52a2e0c0ce..325834268a 100644 --- a/protocol/x/accountplus/authenticator/any_of.go +++ b/protocol/x/accountplus/authenticator/any_of.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) type SignatureAssignment string @@ -19,17 +20,17 @@ const ( ) type AnyOf struct { - SubAuthenticators []Authenticator + SubAuthenticators []types.Authenticator am *AuthenticatorManager signatureAssignment SignatureAssignment } -var _ Authenticator = &AnyOf{} +var _ types.Authenticator = &AnyOf{} func NewAnyOf(am *AuthenticatorManager) AnyOf { return AnyOf{ am: am, - SubAuthenticators: []Authenticator{}, + SubAuthenticators: []types.Authenticator{}, signatureAssignment: Single, } } @@ -37,7 +38,7 @@ func NewAnyOf(am *AuthenticatorManager) AnyOf { func NewPartitionedAnyOf(am *AuthenticatorManager) AnyOf { return AnyOf{ am: am, - SubAuthenticators: []Authenticator{}, + SubAuthenticators: []types.Authenticator{}, signatureAssignment: Partitioned, } } @@ -57,7 +58,7 @@ func (aoa AnyOf) StaticGas() uint64 { return totalGas } -func (aoa AnyOf) Initialize(config []byte) (Authenticator, error) { +func (aoa AnyOf) Initialize(config []byte) (types.Authenticator, error) { // Decode the initialization data for each sub-authenticator var initDatas []SubAuthenticatorInitData if err := json.Unmarshal(config, &initDatas); err != nil { @@ -86,7 +87,7 @@ func (aoa AnyOf) Initialize(config []byte) (Authenticator, error) { return aoa, nil } -func (aoa AnyOf) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AnyOf) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if len(aoa.SubAuthenticators) == 0 { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "no sub-authenticators provided") } @@ -134,13 +135,13 @@ func (aoa AnyOf) Authenticate(ctx sdk.Context, request AuthenticationRequest) er return nil } -func (aoa AnyOf) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AnyOf) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return subTrack(ctx, request, aoa.SubAuthenticators) } // ConfirmExecution is called on all sub-authenticators, but only the changes // made by the authenticator that succeeds are written. -func (aoa AnyOf) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (aoa AnyOf) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { var signatures [][]byte var err error diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go index 0f5216a880..2a20762952 100644 --- a/protocol/x/accountplus/authenticator/clob_pair_id_filter.go +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go @@ -7,10 +7,11 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ) -var _ Authenticator = &ClobPairIdFilter{} +var _ types.Authenticator = &ClobPairIdFilter{} // ClobPairIdFilter filters incoming messages based on a whitelist of clob pair ids. // It ensures that only messages with whitelisted clob pair ids are allowed. @@ -35,7 +36,7 @@ func (m ClobPairIdFilter) StaticGas() uint64 { // Initialize sets up the authenticator with the given configuration, // which should be a list of clob pair ids separated by a predefined separator. -func (m ClobPairIdFilter) Initialize(config []byte) (Authenticator, error) { +func (m ClobPairIdFilter) Initialize(config []byte) (types.Authenticator, error) { strSlice := strings.Split(string(config), SEPARATOR) m.whitelist = make(map[uint32]struct{}) @@ -50,12 +51,12 @@ func (m ClobPairIdFilter) Initialize(config []byte) (Authenticator, error) { } // Track is a no-op in this implementation but can be used to track message handling. -func (m ClobPairIdFilter) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (m ClobPairIdFilter) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } // Authenticate checks if the message's clob pair ids are in the whitelist. -func (m ClobPairIdFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (m ClobPairIdFilter) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { // Collect the clob pair ids from the request. requestOrderIds := make([]uint32, 0) switch msg := request.Msg.(type) { @@ -87,7 +88,7 @@ func (m ClobPairIdFilter) Authenticate(ctx sdk.Context, request AuthenticationRe } // ConfirmExecution confirms the execution of a message. Currently, it always confirms. -func (m ClobPairIdFilter) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (m ClobPairIdFilter) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go index c6d6679f1c..948f588b5a 100644 --- a/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go @@ -10,6 +10,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/stretchr/testify/suite" ) @@ -84,7 +85,7 @@ func (s *ClobPairIdFilterTest) TestFilter() { sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() tx, err := s.GenSimpleTx([]sdk.Msg{tt.msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, diff --git a/protocol/x/accountplus/authenticator/composite.go b/protocol/x/accountplus/authenticator/composite.go index 028d8616cf..b49000fb42 100644 --- a/protocol/x/accountplus/authenticator/composite.go +++ b/protocol/x/accountplus/authenticator/composite.go @@ -7,6 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) type SubAuthenticatorInitData struct { @@ -16,8 +17,8 @@ type SubAuthenticatorInitData struct { func subTrack( ctx sdk.Context, - request AuthenticationRequest, - subAuthenticators []Authenticator, + request types.AuthenticationRequest, + subAuthenticators []types.Authenticator, ) error { baseId := request.AuthenticatorId for id, auth := range subAuthenticators { diff --git a/protocol/x/accountplus/authenticator/composition_test.go b/protocol/x/accountplus/authenticator/composition_test.go index a3ac5da8cd..01b3f1a315 100644 --- a/protocol/x/accountplus/authenticator/composition_test.go +++ b/protocol/x/accountplus/authenticator/composition_test.go @@ -17,6 +17,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/testutils" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) @@ -89,7 +90,7 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOf() { // Define test cases type testCase struct { name string - authenticators []authenticator.Authenticator + authenticators []types.Authenticator expectInit bool expectSuccessful bool expectConfirm bool @@ -98,84 +99,84 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOf() { testCases := []testCase{ { name: "alwaysApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.neverApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "neverApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "alwaysApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "alwaysApprove + alwaysApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "alwaysApprove + alwaysApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove, s.neverApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "alwaysApprove + neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "neverApprove + neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "neverApprove + neverApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "approveAndBlock", - authenticators: []authenticator.Authenticator{s.approveAndBlock}, + authenticators: []types.Authenticator{s.approveAndBlock}, expectInit: false, expectSuccessful: true, expectConfirm: false, }, { name: "rejectAndConfirm", - authenticators: []authenticator.Authenticator{s.rejectAndConfirm}, + authenticators: []types.Authenticator{s.rejectAndConfirm}, expectInit: false, expectSuccessful: false, expectConfirm: true, }, { name: "approveAndBlock + rejectAndConfirm", - authenticators: []authenticator.Authenticator{s.approveAndBlock, s.rejectAndConfirm}, + authenticators: []types.Authenticator{s.approveAndBlock, s.rejectAndConfirm}, expectInit: true, expectSuccessful: true, expectConfirm: true, @@ -213,7 +214,7 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOf() { // sample tx tx, err := s.GenSimpleTx([]sdk.Msg{msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, @@ -247,7 +248,7 @@ func (s *AggregatedAuthenticatorsTest) TestAllOf() { // Define test cases type testCase struct { name string - authenticators []authenticator.Authenticator + authenticators []types.Authenticator expectInit bool expectSuccessful bool expectConfirm bool @@ -256,84 +257,84 @@ func (s *AggregatedAuthenticatorsTest) TestAllOf() { testCases := []testCase{ { name: "alwaysApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "neverApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "alwaysApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "alwaysApprove + alwaysApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: true, expectConfirm: true, }, { name: "alwaysApprove + alwaysApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.alwaysApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.alwaysApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "alwaysApprove + neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.alwaysApprove, s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.alwaysApprove, s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "neverApprove + neverApprove + alwaysApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove, s.alwaysApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove, s.alwaysApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "neverApprove + neverApprove + neverApprove", - authenticators: []authenticator.Authenticator{s.neverApprove, s.neverApprove, s.neverApprove}, + authenticators: []types.Authenticator{s.neverApprove, s.neverApprove, s.neverApprove}, expectInit: true, expectSuccessful: false, expectConfirm: false, }, { name: "approveAndBlock", - authenticators: []authenticator.Authenticator{s.approveAndBlock}, + authenticators: []types.Authenticator{s.approveAndBlock}, expectInit: false, expectSuccessful: true, expectConfirm: false, }, { name: "rejectAndConfirm", - authenticators: []authenticator.Authenticator{s.rejectAndConfirm}, + authenticators: []types.Authenticator{s.rejectAndConfirm}, expectInit: false, expectSuccessful: false, expectConfirm: true, }, { name: "approveAndBlock + rejectAndConfirm", - authenticators: []authenticator.Authenticator{s.approveAndBlock, s.rejectAndConfirm}, + authenticators: []types.Authenticator{s.approveAndBlock, s.rejectAndConfirm}, expectInit: true, expectSuccessful: false, expectConfirm: false, @@ -372,7 +373,7 @@ func (s *AggregatedAuthenticatorsTest) TestAllOf() { tx, err := s.GenSimpleTx([]sdk.Msg{msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) cdc := s.tApp.App.AppCodec() - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, cdc, ak, @@ -401,7 +402,7 @@ func (s *AggregatedAuthenticatorsTest) TestAllOf() { type testAuth struct { name string - authenticator authenticator.Authenticator + authenticator types.Authenticator subAuths []testAuth } @@ -415,7 +416,7 @@ func (s *AggregatedAuthenticatorsTest) TestComposedAuthenticator() { names = append(names, s.name) } name := prefix + "(" + strings.Join(names, ", ") + ")" - var auth authenticator.Authenticator + var auth types.Authenticator if prefix == "AnyOf" { auth = s.AnyOfAuth } else { @@ -484,7 +485,7 @@ func (s *AggregatedAuthenticatorsTest) TestComposedAuthenticator() { // sample tx tx, err := s.GenSimpleTx([]sdk.Msg{msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, @@ -649,7 +650,7 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { data, err := tc.compositeAuth.buildInitData() s.Require().NoError(err) - var auth authenticator.Authenticator + var auth types.Authenticator if tc.compositeAuth.isAllOf() { auth, err = s.AllOfAuth.Initialize(data) s.Require().NoError(err) @@ -667,7 +668,7 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { } // mock the authentication request - authReq := authenticator.AuthenticationRequest{ + authReq := types.AuthenticationRequest{ AuthenticatorId: tc.id, Account: s.TestAccAddress[0], FeePayer: s.TestAccAddress[0], @@ -676,8 +677,8 @@ func (s *AggregatedAuthenticatorsTest) TestNestedAuthenticatorCalls() { Msg: msg, MsgIndex: 0, Signature: []byte{1, 1, 1, 1, 1}, - SignModeTxData: authenticator.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, - SignatureData: authenticator.SimplifiedSignatureData{ + SignModeTxData: types.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, + SignatureData: types.SimplifiedSignatureData{ Signers: []sdk.AccAddress{s.TestAccAddress[0]}, Signatures: [][]byte{{1, 1, 1, 1, 1}}, }, @@ -835,7 +836,7 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOfNotWritingFailedSubAuthState() { data, err := tc.compositeAuth.buildInitData() s.Require().NoError(err) - var auth authenticator.Authenticator + var auth types.Authenticator if tc.compositeAuth.isAllOf() { auth, err = s.AllOfAuth.Initialize(data) s.Require().NoError(err) @@ -853,15 +854,15 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOfNotWritingFailedSubAuthState() { } // mock the authentication request - authReq := authenticator.AuthenticationRequest{ + authReq := types.AuthenticationRequest{ AuthenticatorId: "1", Account: s.TestAccAddress[0], FeePayer: s.TestAccAddress[0], Msg: msg, MsgIndex: 0, Signature: []byte{1, 1, 1, 1, 1}, - SignModeTxData: authenticator.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, - SignatureData: authenticator.SimplifiedSignatureData{ + SignModeTxData: types.SignModeData{Direct: []byte{1, 1, 1, 1, 1}}, + SignatureData: types.SimplifiedSignatureData{ Signers: []sdk.AccAddress{s.TestAccAddress[0]}, Signatures: [][]byte{{1, 1, 1, 1, 1}}, }, diff --git a/protocol/x/accountplus/authenticator/manager.go b/protocol/x/accountplus/authenticator/manager.go index d2ef241055..c4044fa59f 100644 --- a/protocol/x/accountplus/authenticator/manager.go +++ b/protocol/x/accountplus/authenticator/manager.go @@ -1,29 +1,33 @@ package authenticator -import "sort" +import ( + "sort" + + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" +) // AuthenticatorManager is a manager for all registered authenticators. type AuthenticatorManager struct { - registeredAuthenticators map[string]Authenticator + registeredAuthenticators map[string]types.Authenticator orderedKeys []string // slice to keep track of the keys in sorted order } // NewAuthenticatorManager creates a new AuthenticatorManager. func NewAuthenticatorManager() *AuthenticatorManager { return &AuthenticatorManager{ - registeredAuthenticators: make(map[string]Authenticator), + registeredAuthenticators: make(map[string]types.Authenticator), orderedKeys: []string{}, } } // ResetAuthenticators resets all registered authenticators. func (am *AuthenticatorManager) ResetAuthenticators() { - am.registeredAuthenticators = make(map[string]Authenticator) + am.registeredAuthenticators = make(map[string]types.Authenticator) am.orderedKeys = []string{} } // InitializeAuthenticators initializes authenticators. If already initialized, it will not overwrite. -func (am *AuthenticatorManager) InitializeAuthenticators(initialAuthenticators []Authenticator) { +func (am *AuthenticatorManager) InitializeAuthenticators(initialAuthenticators []types.Authenticator) { if len(am.registeredAuthenticators) > 0 { return } @@ -35,7 +39,7 @@ func (am *AuthenticatorManager) InitializeAuthenticators(initialAuthenticators [ } // RegisterAuthenticator adds a new authenticator to the map of registered authenticators. -func (am *AuthenticatorManager) RegisterAuthenticator(authenticator Authenticator) { +func (am *AuthenticatorManager) RegisterAuthenticator(authenticator types.Authenticator) { if _, exists := am.registeredAuthenticators[authenticator.Type()]; !exists { am.orderedKeys = append(am.orderedKeys, authenticator.Type()) sort.Strings(am.orderedKeys) // Re-sort keys after addition @@ -44,7 +48,7 @@ func (am *AuthenticatorManager) RegisterAuthenticator(authenticator Authenticato } // UnregisterAuthenticator removes an authenticator from the map of registered authenticators. -func (am *AuthenticatorManager) UnregisterAuthenticator(authenticator Authenticator) { +func (am *AuthenticatorManager) UnregisterAuthenticator(authenticator types.Authenticator) { if _, exists := am.registeredAuthenticators[authenticator.Type()]; exists { delete(am.registeredAuthenticators, authenticator.Type()) // Remove the key from orderedKeys @@ -58,8 +62,8 @@ func (am *AuthenticatorManager) UnregisterAuthenticator(authenticator Authentica } // GetRegisteredAuthenticators returns the list of registered authenticators in sorted order. -func (am *AuthenticatorManager) GetRegisteredAuthenticators() []Authenticator { - var authenticators []Authenticator +func (am *AuthenticatorManager) GetRegisteredAuthenticators() []types.Authenticator { + var authenticators []types.Authenticator for _, key := range am.orderedKeys { authenticators = append(authenticators, am.registeredAuthenticators[key]) } @@ -73,7 +77,7 @@ func (am *AuthenticatorManager) IsAuthenticatorTypeRegistered(authenticatorType } // GetAuthenticatorByType returns the base implementation of the authenticator type. -func (am *AuthenticatorManager) GetAuthenticatorByType(authenticatorType string) Authenticator { +func (am *AuthenticatorManager) GetAuthenticatorByType(authenticatorType string) types.Authenticator { if authenticator, exists := am.registeredAuthenticators[authenticatorType]; exists { return authenticator } diff --git a/protocol/x/accountplus/authenticator/manager_test.go b/protocol/x/accountplus/authenticator/manager_test.go index 528c0c66a3..3fbb317018 100644 --- a/protocol/x/accountplus/authenticator/manager_test.go +++ b/protocol/x/accountplus/authenticator/manager_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) // Mock Authenticator for testing purposes @@ -24,11 +25,11 @@ func (m MockAuthenticator) OnAuthenticatorRemoved( return nil } -func (m MockAuthenticator) Track(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticator) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } -func (m MockAuthenticator) Initialize(config []byte) (authenticator.Authenticator, error) { +func (m MockAuthenticator) Initialize(config []byte) (types.Authenticator, error) { return m, nil } @@ -36,11 +37,11 @@ func (m MockAuthenticator) StaticGas() uint64 { return 1000 } -func (m MockAuthenticator) Authenticate(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticator) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } -func (m MockAuthenticator) ConfirmExecution(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticator) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } @@ -57,14 +58,14 @@ func (m MockAuthenticator) Type() string { return m.authType } -var _ authenticator.Authenticator = MockAuthenticator{} +var _ types.Authenticator = MockAuthenticator{} func TestInitializeAuthenticators(t *testing.T) { am := authenticator.NewAuthenticatorManager() auth1 := MockAuthenticator{"type1"} auth2 := MockAuthenticator{"type2"} - am.InitializeAuthenticators([]authenticator.Authenticator{auth1, auth2}) + am.InitializeAuthenticators([]types.Authenticator{auth1, auth2}) authenticators := am.GetRegisteredAuthenticators() require.Equal(t, 2, len(authenticators)) @@ -125,11 +126,11 @@ func (m MockAuthenticatorFail) OnAuthenticatorAdded( return nil } -func (m MockAuthenticatorFail) Track(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticatorFail) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } -func (m MockAuthenticatorFail) Initialize(config []byte) (authenticator.Authenticator, error) { +func (m MockAuthenticatorFail) Initialize(config []byte) (types.Authenticator, error) { return m, nil } @@ -137,11 +138,11 @@ func (m MockAuthenticatorFail) StaticGas() uint64 { return 1000 } -func (m MockAuthenticatorFail) Authenticate(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticatorFail) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { return fmt.Errorf("Authentication failed") } -func (m MockAuthenticatorFail) ConfirmExecution(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (m MockAuthenticatorFail) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } @@ -150,8 +151,8 @@ func (m MockAuthenticatorFail) Type() string { } // Ensure our mocks implement the Authenticator interface -var _ authenticator.Authenticator = MockAuthenticator{} -var _ authenticator.Authenticator = MockAuthenticatorFail{} +var _ types.Authenticator = MockAuthenticator{} +var _ types.Authenticator = MockAuthenticatorFail{} // Tests for the mocks behavior func TestMockAuthenticators(t *testing.T) { @@ -163,10 +164,10 @@ func TestMockAuthenticators(t *testing.T) { var mockCtx sdk.Context // Testing mockPass - err := mockPass.Authenticate(mockCtx, authenticator.AuthenticationRequest{}) + err := mockPass.Authenticate(mockCtx, types.AuthenticationRequest{}) require.NoError(t, err) // Testing mockFail - err = mockFail.Authenticate(mockCtx, authenticator.AuthenticationRequest{}) + err = mockFail.Authenticate(mockCtx, types.AuthenticationRequest{}) require.Error(t, err) } diff --git a/protocol/x/accountplus/authenticator/message_filter.go b/protocol/x/accountplus/authenticator/message_filter.go index 9bb1fb9f93..a8bc467aad 100644 --- a/protocol/x/accountplus/authenticator/message_filter.go +++ b/protocol/x/accountplus/authenticator/message_filter.go @@ -7,9 +7,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) -var _ Authenticator = &MessageFilter{} +var _ types.Authenticator = &MessageFilter{} // MessageFilter filters incoming messages based on a predefined JSON pattern. // It allows for complex pattern matching to support advanced authentication flows. @@ -33,7 +34,7 @@ func (m MessageFilter) StaticGas() uint64 { } // Initialize sets up the authenticator with the given data, which should be a valid JSON pattern for message filtering. -func (m MessageFilter) Initialize(config []byte) (Authenticator, error) { +func (m MessageFilter) Initialize(config []byte) (types.Authenticator, error) { strSlice := strings.Split(string(config), SEPARATOR) m.whitelist = make(map[string]struct{}) @@ -44,13 +45,13 @@ func (m MessageFilter) Initialize(config []byte) (Authenticator, error) { } // Track is a no-op in this implementation but can be used to track message handling. -func (m MessageFilter) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (m MessageFilter) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } // Authenticate checks if the provided message conforms to the set JSON pattern. // It returns an AuthenticationResult based on the evaluation. -func (m MessageFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (m MessageFilter) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if _, ok := m.whitelist[sdk.MsgTypeURL(request.Msg)]; !ok { return errorsmod.Wrapf( sdkerrors.ErrUnauthorized, @@ -63,7 +64,7 @@ func (m MessageFilter) Authenticate(ctx sdk.Context, request AuthenticationReque } // ConfirmExecution confirms the execution of a message. Currently, it always confirms. -func (m MessageFilter) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (m MessageFilter) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } diff --git a/protocol/x/accountplus/authenticator/message_filter_test.go b/protocol/x/accountplus/authenticator/message_filter_test.go index 9c389a1c18..42c5edc925 100644 --- a/protocol/x/accountplus/authenticator/message_filter_test.go +++ b/protocol/x/accountplus/authenticator/message_filter_test.go @@ -12,6 +12,7 @@ import ( satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/stretchr/testify/suite" ) @@ -100,7 +101,7 @@ func (s *MessageFilterTest) TestBankSend() { sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() tx, err := s.GenSimpleTx([]sdk.Msg{tt.msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, diff --git a/protocol/x/accountplus/authenticator/signature_authenticator.go b/protocol/x/accountplus/authenticator/signature_authenticator.go index 63a00bd3f6..e3ecce10de 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator.go @@ -4,6 +4,7 @@ import ( "fmt" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" errorsmod "cosmossdk.io/errors" @@ -15,7 +16,7 @@ import ( // Compile time type assertion for the SignatureData using the // SignatureVerification struct -var _ Authenticator = &SignatureVerification{} +var _ types.Authenticator = &SignatureVerification{} const ( // SignatureVerificationType represents a type of authenticator specifically designed for @@ -44,7 +45,7 @@ func NewSignatureVerification(ak authante.AccountKeeper) SignatureVerification { } // Initialize sets up the public key to the data supplied from the account-authenticator configuration -func (sva SignatureVerification) Initialize(config []byte) (Authenticator, error) { +func (sva SignatureVerification) Initialize(config []byte) (types.Authenticator, error) { if len(config) != secp256k1.PubKeySize { sva.PubKey = nil } @@ -54,7 +55,7 @@ func (sva SignatureVerification) Initialize(config []byte) (Authenticator, error // Authenticate takes a SignaturesVerificationData struct and validates // each signer and signature using signature verification -func (sva SignatureVerification) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (sva SignatureVerification) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if request.Simulate || ctx.IsReCheckTx() { return nil } @@ -74,11 +75,11 @@ func (sva SignatureVerification) Authenticate(ctx sdk.Context, request Authentic return nil } -func (sva SignatureVerification) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (sva SignatureVerification) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } -func (sva SignatureVerification) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (sva SignatureVerification) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } diff --git a/protocol/x/accountplus/authenticator/signature_authenticator_test.go b/protocol/x/accountplus/authenticator/signature_authenticator_test.go index 081e52345c..096bd60b45 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator_test.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator_test.go @@ -20,6 +20,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/app/config" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" ) type SigVerifyAuthenticationSuite struct { @@ -266,7 +267,7 @@ func (s *SigVerifyAuthenticationSuite) TestSignatureAuthenticator() { if tc.TestData.ShouldSucceedGettingData { // request for the first message - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, @@ -293,7 +294,7 @@ func (s *SigVerifyAuthenticationSuite) TestSignatureAuthenticator() { s.Require().Error(err) } } else { - _, err := authenticator.GenerateAuthenticationRequest( + _, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, diff --git a/protocol/x/accountplus/authenticator/subaccount_filter.go b/protocol/x/accountplus/authenticator/subaccount_filter.go index 725086f7e1..c36290bc31 100644 --- a/protocol/x/accountplus/authenticator/subaccount_filter.go +++ b/protocol/x/accountplus/authenticator/subaccount_filter.go @@ -7,10 +7,11 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ) -var _ Authenticator = &SubaccountFilter{} +var _ types.Authenticator = &SubaccountFilter{} // SubaccountFilter filters incoming messages based on a whitelist of subaccount numbers. // It ensures that only messages with whitelisted subaccount numbers are allowed. @@ -35,7 +36,7 @@ func (m SubaccountFilter) StaticGas() uint64 { // Initialize sets up the authenticator with the given data, // which should be a string of subaccount numbers separated by the specified separator. -func (m SubaccountFilter) Initialize(config []byte) (Authenticator, error) { +func (m SubaccountFilter) Initialize(config []byte) (types.Authenticator, error) { strSlice := strings.Split(string(config), SEPARATOR) m.whitelist = make(map[uint32]struct{}) @@ -50,12 +51,12 @@ func (m SubaccountFilter) Initialize(config []byte) (Authenticator, error) { } // Track is a no-op in this implementation but can be used to track message handling. -func (m SubaccountFilter) Track(ctx sdk.Context, request AuthenticationRequest) error { +func (m SubaccountFilter) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } // Authenticate checks if the message's subaccount numbers are in the whitelist. -func (m SubaccountFilter) Authenticate(ctx sdk.Context, request AuthenticationRequest) error { +func (m SubaccountFilter) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { // Collect the clob pair ids from the request. requestSubaccountNums := make([]uint32, 0) switch msg := request.Msg.(type) { @@ -85,7 +86,7 @@ func (m SubaccountFilter) Authenticate(ctx sdk.Context, request AuthenticationRe } // ConfirmExecution confirms the execution of a message. Currently, it always confirms. -func (m SubaccountFilter) ConfirmExecution(ctx sdk.Context, request AuthenticationRequest) error { +func (m SubaccountFilter) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } diff --git a/protocol/x/accountplus/authenticator/subaccount_filter_test.go b/protocol/x/accountplus/authenticator/subaccount_filter_test.go index dbb703a9f3..09f6e85eb8 100644 --- a/protocol/x/accountplus/authenticator/subaccount_filter_test.go +++ b/protocol/x/accountplus/authenticator/subaccount_filter_test.go @@ -10,6 +10,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/stretchr/testify/suite" ) @@ -84,7 +85,7 @@ func (s *SubaccountFilterTest) TestFilter() { sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() tx, err := s.GenSimpleTx([]sdk.Msg{tt.msg}, []cryptotypes.PrivKey{s.TestPrivKeys[0]}) s.Require().NoError(err) - request, err := authenticator.GenerateAuthenticationRequest( + request, err := lib.GenerateAuthenticationRequest( s.Ctx, s.tApp.App.AppCodec(), ak, diff --git a/protocol/x/accountplus/keeper/authenticators.go b/protocol/x/accountplus/keeper/authenticators.go index 2ecbeb7dff..fc2ac0c013 100644 --- a/protocol/x/accountplus/keeper/authenticators.go +++ b/protocol/x/accountplus/keeper/authenticators.go @@ -12,7 +12,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" gogotypes "github.com/cosmos/gogoproto/types" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" - "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) @@ -144,11 +143,11 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( ctx sdk.Context, account sdk.AccAddress, selectedAuthenticator uint64, -) (authenticator.InitializedAuthenticator, error) { +) (types.InitializedAuthenticator, error) { // Get the authenticator data from the store authenticatorFromStore, err := k.GetSelectedAuthenticatorData(ctx, account, selectedAuthenticator) if err != nil { - return authenticator.InitializedAuthenticator{}, err + return types.InitializedAuthenticator{}, err } uninitializedAuthenticator := k.authenticatorManager.GetAuthenticatorByType(authenticatorFromStore.Type) @@ -163,7 +162,7 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( "account", account.String(), ) - return authenticator.InitializedAuthenticator{}, + return types.InitializedAuthenticator{}, errors.Wrapf( sdkerrors.ErrLogic, "authenticator id %d failed to initialize for account %s, authenticator type %s not registered in manager", @@ -175,7 +174,7 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( // NOTE: The authenticator manager returns a struct that is reused initializedAuthenticator, err := uninitializedAuthenticator.Initialize(authenticatorFromStore.Config) if err != nil { - return authenticator.InitializedAuthenticator{}, + return types.InitializedAuthenticator{}, errors.Wrapf( err, "authenticator %d with type %s failed to initialize for account %s", @@ -183,7 +182,7 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( ) } if initializedAuthenticator == nil { - return authenticator.InitializedAuthenticator{}, + return types.InitializedAuthenticator{}, errors.Wrapf( types.ErrInitializingAuthenticator, "authenticator.Initialize returned nil for %d with type %s for account %s", @@ -191,7 +190,7 @@ func (k Keeper) GetInitializedAuthenticatorForAccount( ) } - finalAuthenticator := authenticator.InitializedAuthenticator{ + finalAuthenticator := types.InitializedAuthenticator{ Id: authenticatorFromStore.Id, Authenticator: initializedAuthenticator, } diff --git a/protocol/x/accountplus/keeper/keeper_test.go b/protocol/x/accountplus/keeper/keeper_test.go index 19f3991c89..bb0d2d0bbb 100644 --- a/protocol/x/accountplus/keeper/keeper_test.go +++ b/protocol/x/accountplus/keeper/keeper_test.go @@ -35,7 +35,7 @@ func (s *KeeperTestSuite) SetupTest() { s.tApp.App.AuthenticatorManager.ResetAuthenticators() s.tApp.App.AuthenticatorManager.InitializeAuthenticators( - []authenticator.Authenticator{ + []types.Authenticator{ authenticator.SignatureVerification{}, authenticator.MessageFilter{}, testutils.TestingAuthenticator{ diff --git a/protocol/x/accountplus/authenticator/authentication_request.go b/protocol/x/accountplus/lib/authentication_request.go similarity index 77% rename from protocol/x/accountplus/authenticator/authentication_request.go rename to protocol/x/accountplus/lib/authentication_request.go index 7beab1f930..32687f1fda 100644 --- a/protocol/x/accountplus/authenticator/authentication_request.go +++ b/protocol/x/accountplus/lib/authentication_request.go @@ -1,4 +1,4 @@ -package authenticator +package lib import ( "fmt" @@ -6,6 +6,7 @@ import ( txsigning "cosmossdk.io/x/tx/signing" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" @@ -16,32 +17,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// -// These structs define the data structure for authentication, used with AuthenticationRequest struct. -// - -// SignModeData represents the signing modes with direct bytes and textual representation. -type SignModeData struct { - Direct []byte `json:"sign_mode_direct"` - Textual string `json:"sign_mode_textual"` -} - -// SimplifiedSignatureData contains lists of signers and their corresponding signatures. -type SimplifiedSignatureData struct { - Signers []sdk.AccAddress `json:"signers"` - Signatures [][]byte `json:"signatures"` -} - -// ExplicitTxData encapsulates key transaction data like chain ID, account info, and messages. -type ExplicitTxData struct { - ChainID string `json:"chain_id"` - AccountNumber uint64 `json:"account_number"` - AccountSequence uint64 `json:"sequence"` - TimeoutHeight uint64 `json:"timeout_height"` - Msgs []sdk.Msg `json:"msgs"` - Memo string `json:"memo"` -} - // GetSignerAndSignatures gets an array of signer and an array of signatures from the transaction // checks they're the same length and returns both. // @@ -113,17 +88,17 @@ func getSignerData(ctx sdk.Context, ak authante.AccountKeeper, account sdk.AccAd // extractExplicitTxData makes the transaction data concrete for the authentication request. This is necessary to // pass the parsed data to the cosmwasm authenticator. -func extractExplicitTxData(tx sdk.Tx, signerData authsigning.SignerData) (ExplicitTxData, error) { +func extractExplicitTxData(tx sdk.Tx, signerData authsigning.SignerData) (types.ExplicitTxData, error) { timeoutTx, ok := tx.(sdk.TxWithTimeoutHeight) if !ok { - return ExplicitTxData{}, errorsmod.Wrap(sdkerrors.ErrInvalidType, "failed to cast tx to TxWithTimeoutHeight") + return types.ExplicitTxData{}, errorsmod.Wrap(sdkerrors.ErrInvalidType, "failed to cast tx to TxWithTimeoutHeight") } memoTx, ok := tx.(sdk.TxWithMemo) if !ok { - return ExplicitTxData{}, errorsmod.Wrap(sdkerrors.ErrInvalidType, "failed to cast tx to TxWithMemo") + return types.ExplicitTxData{}, errorsmod.Wrap(sdkerrors.ErrInvalidType, "failed to cast tx to TxWithMemo") } - return ExplicitTxData{ + return types.ExplicitTxData{ ChainID: signerData.ChainID, AccountNumber: signerData.AccountNumber, AccountSequence: signerData.Sequence, @@ -180,15 +155,15 @@ func GenerateAuthenticationRequest( tx sdk.Tx, msgIndex int, simulate bool, -) (AuthenticationRequest, error) { +) (types.AuthenticationRequest, error) { // Only supporting one signer per message. This will be enforced in sdk v0.50 signers, _, err := cdc.GetMsgV1Signers(msg) if err != nil { - return AuthenticationRequest{}, err + return types.AuthenticationRequest{}, err } signer := sdk.AccAddress(signers[0]) if !signer.Equals(account) { - return AuthenticationRequest{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid signer") + return types.AuthenticationRequest{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid signer") } // Get the signers and signatures from the transaction. A signer can only have one signature, so if it @@ -197,7 +172,7 @@ func GenerateAuthenticationRequest( // to change this in the future txSigners, txSignatures, err := GetSignerAndSignatures(tx) if err != nil { - return AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signers and signatures") + return types.AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signers and signatures") } // Get the signer data for the account. This is needed in the SignDoc @@ -206,17 +181,17 @@ func GenerateAuthenticationRequest( // Get the concrete transaction data to be passed to the authenticators txData, err := extractExplicitTxData(tx, signerData) if err != nil { - return AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get explicit tx data") + return types.AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get explicit tx data") } // Get the signatures for the transaction and execute replay protection signatures, msgSignature, err := extractSignatures(txSigners, txSignatures, account) if err != nil { - return AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signatures") + return types.AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signatures") } // Build the authentication request - authRequest := AuthenticationRequest{ + authRequest := types.AuthenticationRequest{ Account: account, FeePayer: feePayer, FeeGranter: feeGranter, @@ -225,10 +200,10 @@ func GenerateAuthenticationRequest( MsgIndex: uint64(msgIndex), Signature: msgSignature, TxData: txData, - SignModeTxData: SignModeData{ + SignModeTxData: types.SignModeData{ Direct: []byte("signBytes"), }, - SignatureData: SimplifiedSignatureData{ + SignatureData: types.SimplifiedSignatureData{ Signers: txSigners, Signatures: signatures, }, @@ -250,11 +225,11 @@ func GenerateAuthenticationRequest( tx, ) if err != nil { - return AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signBytes") + return types.AuthenticationRequest{}, errorsmod.Wrap(err, "failed to get signBytes") } // TODO: Add other sign modes. Specifically json when it becomes available - authRequest.SignModeTxData = SignModeData{ + authRequest.SignModeTxData = types.SignModeData{ Direct: signBytes, } diff --git a/protocol/x/accountplus/testutils/generic_authenticator.go b/protocol/x/accountplus/testutils/generic_authenticator.go index ed42d30828..42709e658e 100644 --- a/protocol/x/accountplus/testutils/generic_authenticator.go +++ b/protocol/x/accountplus/testutils/generic_authenticator.go @@ -7,11 +7,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) var ( - _ authenticator.Authenticator = &TestingAuthenticator{} + _ types.Authenticator = &TestingAuthenticator{} ) type ApproveOn int @@ -59,11 +59,11 @@ func (t TestingAuthenticator) StaticGas() uint64 { return uint64(t.GasConsumption) } -func (t TestingAuthenticator) Initialize(config []byte) (authenticator.Authenticator, error) { +func (t TestingAuthenticator) Initialize(config []byte) (types.Authenticator, error) { return t, nil } -func (t TestingAuthenticator) Authenticate(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (t TestingAuthenticator) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if t.Approve == Always { return nil } else { @@ -71,11 +71,11 @@ func (t TestingAuthenticator) Authenticate(ctx sdk.Context, request authenticato } } -func (t TestingAuthenticator) Track(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (t TestingAuthenticator) Track(ctx sdk.Context, request types.AuthenticationRequest) error { return nil } -func (t TestingAuthenticator) ConfirmExecution(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (t TestingAuthenticator) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { if t.Confirm == Always { return nil } else { diff --git a/protocol/x/accountplus/testutils/spy_authenticator.go b/protocol/x/accountplus/testutils/spy_authenticator.go index f694f5fd0e..3955d4dde3 100644 --- a/protocol/x/accountplus/testutils/spy_authenticator.go +++ b/protocol/x/accountplus/testutils/spy_authenticator.go @@ -10,10 +10,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) -var _ authenticator.Authenticator = &SpyAuthenticator{} +var _ types.Authenticator = &SpyAuthenticator{} type SpyAuthenticateRequest struct { AuthenticatorId string `json:"authenticator_id"` @@ -92,7 +92,7 @@ func (s SpyAuthenticator) StaticGas() uint64 { return 1000 } -func (s SpyAuthenticator) Initialize(config []byte) (authenticator.Authenticator, error) { +func (s SpyAuthenticator) Initialize(config []byte) (types.Authenticator, error) { var spyData SpyAuthenticatorData err := json.Unmarshal(config, &spyData) if err != nil { @@ -103,7 +103,7 @@ func (s SpyAuthenticator) Initialize(config []byte) (authenticator.Authenticator return s, nil } -func (s SpyAuthenticator) Authenticate(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (s SpyAuthenticator) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { bz := s.Cdc.MustMarshal(request.Msg) calls.Authenticate = SpyAuthenticateRequest{ @@ -121,7 +121,7 @@ func (s SpyAuthenticator) Authenticate(ctx sdk.Context, request authenticator.Au return nil } -func (s SpyAuthenticator) Track(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (s SpyAuthenticator) Track(ctx sdk.Context, request types.AuthenticationRequest) error { s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { bz := s.Cdc.MustMarshal(request.Msg) calls.Track = SpyTrackRequest{ @@ -135,7 +135,7 @@ func (s SpyAuthenticator) Track(ctx sdk.Context, request authenticator.Authentic return nil } -func (s SpyAuthenticator) ConfirmExecution(ctx sdk.Context, request authenticator.AuthenticationRequest) error { +func (s SpyAuthenticator) ConfirmExecution(ctx sdk.Context, request types.AuthenticationRequest) error { // intentionlly call update before check to test state revert s.UpdateLatestCalls(ctx, func(calls LatestCalls) LatestCalls { bz := s.Cdc.MustMarshal(request.Msg) diff --git a/protocol/x/accountplus/authenticator/iface.go b/protocol/x/accountplus/types/iface.go similarity index 99% rename from protocol/x/accountplus/authenticator/iface.go rename to protocol/x/accountplus/types/iface.go index 556d6d0367..b1a048cfdc 100644 --- a/protocol/x/accountplus/authenticator/iface.go +++ b/protocol/x/accountplus/types/iface.go @@ -1,4 +1,4 @@ -package authenticator +package types import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/protocol/x/accountplus/authenticator/requests.go b/protocol/x/accountplus/types/requests.go similarity index 69% rename from protocol/x/accountplus/authenticator/requests.go rename to protocol/x/accountplus/types/requests.go index 54647a00dc..c0db46e195 100644 --- a/protocol/x/accountplus/authenticator/requests.go +++ b/protocol/x/accountplus/types/requests.go @@ -1,9 +1,35 @@ -package authenticator +package types import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// +// These structs define the data structure for authentication, used with AuthenticationRequest struct. +// + +// SignModeData represents the signing modes with direct bytes and textual representation. +type SignModeData struct { + Direct []byte `json:"sign_mode_direct"` + Textual string `json:"sign_mode_textual"` +} + +// SimplifiedSignatureData contains lists of signers and their corresponding signatures. +type SimplifiedSignatureData struct { + Signers []sdk.AccAddress `json:"signers"` + Signatures [][]byte `json:"signatures"` +} + +// ExplicitTxData encapsulates key transaction data like chain ID, account info, and messages. +type ExplicitTxData struct { + ChainID string `json:"chain_id"` + AccountNumber uint64 `json:"account_number"` + AccountSequence uint64 `json:"sequence"` + TimeoutHeight uint64 `json:"timeout_height"` + Msgs []sdk.Msg `json:"msgs"` + Memo string `json:"memo"` +} + type TrackRequest struct { AuthenticatorId string `json:"authenticator_id"` Account sdk.AccAddress `json:"account"` From ca5e96d66d5d17f2cd3a8926cf962fd6f609776b Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:17:34 -0400 Subject: [PATCH 059/120] Add tests for when market pair name changes (#2280) --- protocol/testing/e2e/gov/prices_test.go | 14 +++++ .../msg_server_update_market_param_test.go | 57 ++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/protocol/testing/e2e/gov/prices_test.go b/protocol/testing/e2e/gov/prices_test.go index 89f2b996b8..ad341b83b3 100644 --- a/protocol/testing/e2e/gov/prices_test.go +++ b/protocol/testing/e2e/gov/prices_test.go @@ -67,6 +67,20 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, }, + "Failure: new pair name does not exist in marketmap": { + msg: &pricestypes.MsgUpdateMarketParam{ + Authority: lib.GovModuleAddress.String(), + MarketParam: pricestypes.MarketParam{ + Id: MODIFIED_MARKET_PARAM.Id, + Pair: "nonexistent-pair", + Exponent: MODIFIED_MARKET_PARAM.Exponent, + MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, + MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, + ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, + }, + }, + expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, + }, "Failure: exponent is updated": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), diff --git a/protocol/x/prices/keeper/msg_server_update_market_param_test.go b/protocol/x/prices/keeper/msg_server_update_market_param_test.go index b04959a7a6..5e837330e8 100644 --- a/protocol/x/prices/keeper/msg_server_update_market_param_test.go +++ b/protocol/x/prices/keeper/msg_server_update_market_param_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper" @@ -26,7 +27,7 @@ func TestUpdateMarketParam(t *testing.T) { msg *pricestypes.MsgUpdateMarketParam expectedErr string }{ - "Succeeds: update all parameters except exponent": { + "Succeeds: update all parameters except exponent and pair": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), MarketParam: pricestypes.MarketParam{ @@ -39,6 +40,19 @@ func TestUpdateMarketParam(t *testing.T) { }, }, }, + "Succeeds: update pair name": { + msg: &pricestypes.MsgUpdateMarketParam{ + Authority: lib.GovModuleAddress.String(), + MarketParam: pricestypes.MarketParam{ + Id: testMarketParam.Id, + Pair: "NEWMARKET-USD", + Exponent: testMarketParam.Exponent, + MinExchanges: 72, + MinPriceChangePpm: 2_023, + ExchangeConfigJson: `{"exchanges":[{"exchangeName":"XYZ","ticker":"PIKACHU"}]}`, + }, + }, + }, "Succeeds: update min price change ppm only": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), @@ -122,6 +136,20 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedErr: "Market exponent cannot be updated", }, + "Failure: new pair name does not exist in marketmap": { + msg: &pricestypes.MsgUpdateMarketParam{ + Authority: lib.GovModuleAddress.String(), + MarketParam: pricestypes.MarketParam{ + Id: testMarketParam.Id, + Pair: "nonexistent-pair", + Exponent: testMarketParam.Exponent, + MinExchanges: testMarketParam.MinExchanges, + MinPriceChangePpm: testMarketParam.MinPriceChangePpm, + ExchangeConfigJson: "{}", + }, + }, + expectedErr: "NONEXISTENT/PAIR: Ticker not found in market map", + }, "Failure: empty authority": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: "", @@ -144,12 +172,22 @@ func TestUpdateMarketParam(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - ctx, pricesKeeper, _, _, mockTimeProvider, _, _ := keepertest.PricesKeepers(t) + ctx, pricesKeeper, _, _, mockTimeProvider, _, marketMapKeeper := keepertest.PricesKeepers(t) mockTimeProvider.On("Now").Return(constants.TimeT) msgServer := keeper.NewMsgServerImpl(pricesKeeper) initialMarketParam, err := keepertest.CreateTestMarket(t, ctx, pricesKeeper, testMarketParam, testMarketPrice) require.NoError(t, err) + // Create new pair in marketmap if test is expected to succeed + if (initialMarketParam.Pair != tc.msg.MarketParam.Pair) && tc.expectedErr == "" { + keepertest.CreateMarketsInMarketMapFromParams( + t, + ctx, + marketMapKeeper, + []pricestypes.MarketParam{tc.msg.MarketParam}, + ) + } + _, err = msgServer.UpdateMarketParam(ctx, tc.msg) if tc.expectedErr != "" { require.ErrorContains(t, err, tc.expectedErr) @@ -163,6 +201,21 @@ func TestUpdateMarketParam(t *testing.T) { updatedMarketParam, exists := pricesKeeper.GetMarketParam(ctx, tc.msg.MarketParam.Id) require.True(t, exists) require.Equal(t, tc.msg.MarketParam, updatedMarketParam) + + // If pair name changed, verify that old pair is disabled in the marketmap and new pair is enabled + if initialMarketParam.Pair != updatedMarketParam.Pair { + oldCp, err := slinky.MarketPairToCurrencyPair(initialMarketParam.Pair) + require.NoError(t, err) + oldMarket, err := marketMapKeeper.GetMarket(ctx, oldCp.String()) + require.NoError(t, err) + require.False(t, oldMarket.Ticker.Enabled) + + newCp, err := slinky.MarketPairToCurrencyPair(updatedMarketParam.Pair) + require.NoError(t, err) + market, err := marketMapKeeper.GetMarket(ctx, newCp.String()) + require.NoError(t, err) + require.True(t, market.Ticker.Enabled) + } } }) } From 253f98d8168cd7608bb44a526784773a66e21ede Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Tue, 1 Oct 2024 17:12:55 -0400 Subject: [PATCH 060/120] chore: Bump Cometbft to log proposer when proposal is rejected (#2421) --- protocol/go.mod | 2 +- protocol/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/go.mod b/protocol/go.mod index b70383c5a5..b2224d6ad0 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -463,7 +463,7 @@ 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.20240426214049-c8beeeada40a + github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf // Use dYdX fork of Cosmos SDK github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703 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 01989606e0..e3611326e6 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -953,8 +953,8 @@ 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.20240426214049-c8beeeada40a h1:KeQZZsYJQ/AKQ6lbP5lL3N/6aOclxxYG8pIm8zerwZw= -github.com/dydxprotocol/cometbft v0.38.6-0.20240426214049-c8beeeada40a/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= +github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf h1:pdKqF/qshVtVxcCfpK93QSUIIV3UjR/zj0RfPuqFPwU= +github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703 h1:4bNZ3j0dhbxWfqyEKc0sC2377m+t+wFuFDocqig9VLo= github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703/go.mod h1:TWUDGvgHJ49+QI6WOf03km3TuUOoAplzgnsjGQH3L7s= github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d h1:HgLu1FD2oDFzlKW6/+SFXlH5Os8cwNTbplQIrQOWx8w= From 753bac8abe1f2795763f3f708d991bb196dbfd52 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:42:51 -0400 Subject: [PATCH 061/120] [TRA-611] Get MarketPrice exponent from marketmap (#2324) --- .../dydxprotocol/prices/market_param.ts | 8 ++ .../dydxprotocol/prices/market_price.ts | 6 ++ proto/dydxprotocol/prices/market_param.proto | 4 +- proto/dydxprotocol/prices/market_price.proto | 3 + protocol/app/ante/market_update_test.go | 13 +-- protocol/mocks/PricesKeeper.go | 28 +++++ protocol/testing/e2e/gov/prices_test.go | 14 --- protocol/testutil/app/order.go | 10 +- protocol/testutil/constants/genesis.go | 12 +-- protocol/x/prices/keeper/market.go | 31 +++++- protocol/x/prices/keeper/market_param.go | 4 - protocol/x/prices/keeper/market_price.go | 12 ++- protocol/x/prices/keeper/market_test.go | 101 +++++++++++++----- .../keeper/msg_server_create_oracle_market.go | 7 +- .../msg_server_create_oracle_market_test.go | 64 +++++++++-- .../msg_server_update_market_param_test.go | 14 --- protocol/x/prices/module_test.go | 8 -- protocol/x/prices/simulation/genesis.go | 3 + protocol/x/prices/types/errors.go | 11 +- protocol/x/prices/types/market_param.pb.go | 43 ++++---- protocol/x/prices/types/market_price.go | 10 -- protocol/x/prices/types/market_price.pb.go | 3 + protocol/x/prices/types/types.go | 1 + 23 files changed, 284 insertions(+), 126 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts index d945e1c82f..95ed7d6c89 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts @@ -18,8 +18,12 @@ export interface MarketParam { * For example if `Exponent == -5` then a `Value` of `1,000,000,000` * represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest * price step (in dollars) that can be recorded. + * + * Deprecated since v7.1.x. This value is now determined from the marketmap. */ + /** @deprecated */ + exponent: number; /** * The minimum number of exchanges that should be reporting a live price for @@ -58,8 +62,12 @@ export interface MarketParamSDKType { * For example if `Exponent == -5` then a `Value` of `1,000,000,000` * represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest * price step (in dollars) that can be recorded. + * + * Deprecated since v7.1.x. This value is now determined from the marketmap. */ + /** @deprecated */ + exponent: number; /** * The minimum number of exchanges that should be reporting a live price for diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_price.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_price.ts index e8cd1ae596..5320c2c801 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_price.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_price.ts @@ -8,6 +8,9 @@ export interface MarketPrice { /** * Static value. The exponent of the price. See the comment on the duplicate * MarketParam field for more information. + * + * As of v7.1.x, this value is determined from the marketmap instead of + * needing to match the MarketParam field. */ exponent: number; @@ -26,6 +29,9 @@ export interface MarketPriceSDKType { /** * Static value. The exponent of the price. See the comment on the duplicate * MarketParam field for more information. + * + * As of v7.1.x, this value is determined from the marketmap instead of + * needing to match the MarketParam field. */ exponent: number; diff --git a/proto/dydxprotocol/prices/market_param.proto b/proto/dydxprotocol/prices/market_param.proto index 0ad48809bd..4b90b2877b 100644 --- a/proto/dydxprotocol/prices/market_param.proto +++ b/proto/dydxprotocol/prices/market_param.proto @@ -18,7 +18,9 @@ message MarketParam { // For example if `Exponent == -5` then a `Value` of `1,000,000,000` // represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest // price step (in dollars) that can be recorded. - sint32 exponent = 3; + // + // Deprecated since v7.1.x. This value is now determined from the marketmap. + sint32 exponent = 3 [ deprecated = true ]; // The minimum number of exchanges that should be reporting a live price for // a price update to be considered valid. diff --git a/proto/dydxprotocol/prices/market_price.proto b/proto/dydxprotocol/prices/market_price.proto index acfd996750..a77078bc78 100644 --- a/proto/dydxprotocol/prices/market_price.proto +++ b/proto/dydxprotocol/prices/market_price.proto @@ -10,6 +10,9 @@ message MarketPrice { // Static value. The exponent of the price. See the comment on the duplicate // MarketParam field for more information. + // + // As of v7.1.x, this value is determined from the marketmap instead of + // needing to match the MarketParam field. sint32 exponent = 2; // The variable value that is updated by oracle price updates. `0` if it has diff --git a/protocol/app/ante/market_update_test.go b/protocol/app/ante/market_update_test.go index 9fc6c49e8e..d97cb91fab 100644 --- a/protocol/app/ante/market_update_test.go +++ b/protocol/app/ante/market_update_test.go @@ -4,8 +4,9 @@ import ( "math/rand" "testing" - sdkmath "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" + + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -184,7 +185,7 @@ var ( Base: "TESTING", Quote: "USD", }, - Decimals: 1, + Decimals: 8, MinProviderCount: 1, Enabled: false, Metadata_JSON: "", @@ -198,7 +199,7 @@ var ( Base: "TESTING", Quote: "USD", }, - Decimals: 1, + Decimals: 8, MinProviderCount: 1, Enabled: false, Metadata_JSON: "", @@ -236,7 +237,7 @@ var ( Base: "TESTING", Quote: "USD", }, - Decimals: 1, + Decimals: 8, MinProviderCount: 1, Enabled: true, Metadata_JSON: "", @@ -255,7 +256,7 @@ var ( Base: "TESTING", Quote: "USD", }, - Decimals: 1, + Decimals: 8, MinProviderCount: 1, Enabled: true, Metadata_JSON: "", @@ -841,7 +842,7 @@ func TestValidateMarketUpdateDecorator_AnteHandle(t *testing.T) { ctx, mmtypes.Market{ Ticker: mmtypes.Ticker{ - Decimals: uint64(pair.market.Exponent), + Decimals: uint64(pair.market.Exponent * -1), Enabled: false, // will be enabled later CurrencyPair: cp, }, diff --git a/protocol/mocks/PricesKeeper.go b/protocol/mocks/PricesKeeper.go index f2e053b193..7eecd7edb1 100644 --- a/protocol/mocks/PricesKeeper.go +++ b/protocol/mocks/PricesKeeper.go @@ -150,6 +150,34 @@ func (_m *PricesKeeper) GetCurrencyPairFromID(ctx types.Context, id uint64) (pkg return r0, r1 } +// GetExponent provides a mock function with given fields: ctx, ticker +func (_m *PricesKeeper) GetExponent(ctx types.Context, ticker string) (int32, error) { + ret := _m.Called(ctx, ticker) + + if len(ret) == 0 { + panic("no return value specified for GetExponent") + } + + var r0 int32 + var r1 error + if rf, ok := ret.Get(0).(func(types.Context, string) (int32, error)); ok { + return rf(ctx, ticker) + } + if rf, ok := ret.Get(0).(func(types.Context, string) int32); ok { + r0 = rf(ctx, ticker) + } else { + r0 = ret.Get(0).(int32) + } + + if rf, ok := ret.Get(1).(func(types.Context, string) error); ok { + r1 = rf(ctx, ticker) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetIDForCurrencyPair provides a mock function with given fields: ctx, cp func (_m *PricesKeeper) GetIDForCurrencyPair(ctx types.Context, cp pkgtypes.CurrencyPair) (uint64, bool) { ret := _m.Called(ctx, cp) diff --git a/protocol/testing/e2e/gov/prices_test.go b/protocol/testing/e2e/gov/prices_test.go index ad341b83b3..e6b77c5ec9 100644 --- a/protocol/testing/e2e/gov/prices_test.go +++ b/protocol/testing/e2e/gov/prices_test.go @@ -81,20 +81,6 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, }, - "Failure: exponent is updated": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id, - Pair: MODIFIED_MARKET_PARAM.Pair, - Exponent: MODIFIED_MARKET_PARAM.Exponent + 1, // update to exponent is not permitted. - MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, - }, - }, - expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, - }, "Failure: empty pair": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), diff --git a/protocol/testutil/app/order.go b/protocol/testutil/app/order.go index 69cd7208f1..56a2096f8c 100644 --- a/protocol/testutil/app/order.go +++ b/protocol/testutil/app/order.go @@ -40,11 +40,17 @@ func MustMakeOrderFromHumanInput( if !exists { panic(fmt.Sprintf("marketParam does not exist: %v", perp.Params.MarketId)) } - marketPrice := pricestest.MustHumanPriceToMarketPrice(humanPrice, marketParams.Exponent) + + exponent, err := app.PricesKeeper.GetExponent(ctx, marketParams.Pair) + if err != nil { + panic(err) + } + + marketPrice := pricestest.MustHumanPriceToMarketPrice(humanPrice, exponent) subticks := clobtypes.PriceToSubticks( pricestypes.MarketPrice{ Price: marketPrice, - Exponent: marketParams.Exponent, + Exponent: exponent, }, clobPair, perp.Params.AtomicResolution, diff --git a/protocol/testutil/constants/genesis.go b/protocol/testutil/constants/genesis.go index f56364819b..2c679ec3ed 100644 --- a/protocol/testutil/constants/genesis.go +++ b/protocol/testutil/constants/genesis.go @@ -4007,7 +4007,7 @@ const GenesisState = `{ }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"LINKUSDT\\\"\"},{\"exchangeName\":\"BinanceUS\",\"ticker\":\"\\\"LINKUSD\\\"\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LINK-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"LINK_USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"linkusdt\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"LINKUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LINK-USDT\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LINK-USDT\"}]}", - "exponent": -8, + "exponent": -9, "id": 2, "min_exchanges": 1, "min_price_change_ppm": 2000, @@ -4175,7 +4175,7 @@ const GenesisState = `{ }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"MKRUSDT\\\"\"},{\"exchangeName\":\"BinanceUS\",\"ticker\":\"\\\"MKRUSD\\\"\"},{\"exchangeName\":\"Bitfinex\",\"ticker\":\"tMKRUSD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MKR-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MKR_USDT\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"mkrusdt\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MKR-USDT\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MKR-USDT\"}]}", - "exponent": -7, + "exponent": -6, "id": 23, "min_exchanges": 1, "min_price_change_ppm": 2000, @@ -4191,7 +4191,7 @@ const GenesisState = `{ }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"XLMUSDT\\\"\"},{\"exchangeName\":\"BinanceUS\",\"ticker\":\"\\\"XLMUSD\\\"\"},{\"exchangeName\":\"Bitfinex\",\"ticker\":\"tXLMUSD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"XLM-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"XLM_USDT\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XXLMZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"XLM-USDT\"},{\"exchangeName\":\"Okx\",\"ticker\":\"XLM-USDT\"}]}", - "exponent": -11, + "exponent": -10, "id": 25, "min_exchanges": 1, "min_price_change_ppm": 2000, @@ -4266,7 +4266,7 @@ const GenesisState = `{ "price": 1500000000 }, { - "exponent": -8, + "exponent": -9, "id": 2, "price": 700000000 }, @@ -4371,7 +4371,7 @@ const GenesisState = `{ "price": 2200000000 }, { - "exponent": -7, + "exponent": -6, "id": 23, "price": 7100000000 }, @@ -4381,7 +4381,7 @@ const GenesisState = `{ "price": 7000000000 }, { - "exponent": -11, + "exponent": -10, "id": 25, "price": 10000000000 }, diff --git a/protocol/x/prices/keeper/market.go b/protocol/x/prices/keeper/market.go index 8a7fde8dd8..d5c76cc310 100644 --- a/protocol/x/prices/keeper/market.go +++ b/protocol/x/prices/keeper/market.go @@ -57,7 +57,7 @@ func (k Keeper) CreateMarket( ) } currencyPairStr := currencyPair.String() - _, err = k.MarketMapKeeper.GetMarket(ctx, currencyPairStr) + marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, currencyPairStr) if err != nil { return types.MarketParam{}, errorsmod.Wrapf( types.ErrTickerNotFoundInMarketMap, @@ -65,6 +65,14 @@ func (k Keeper) CreateMarket( ) } + // Check that the exponent of market price is the negation of the decimals value in the market map + if marketPrice.Exponent != int32(marketMapDetails.Ticker.Decimals)*-1 { + return types.MarketParam{}, errorsmod.Wrapf( + types.ErrInvalidMarketPriceExponent, + currencyPairStr, + ) + } + paramBytes := k.cdc.MustMarshal(&marketParam) priceBytes := k.cdc.MustMarshal(&marketPrice) @@ -87,7 +95,8 @@ func (k Keeper) CreateMarket( marketParam.Id, marketParam.Pair, marketParam.MinPriceChangePpm, - marketParam.Exponent, + // The exponent in market price is the source of truth, the exponent of the param is deprecated as of v7.1.x + marketPrice.Exponent, ), ), ) @@ -111,6 +120,24 @@ func (k Keeper) CreateMarket( return marketParam, nil } +// Get the exponent for a market as the negation of the decimals value in the market map +func (k Keeper) GetExponent(ctx sdk.Context, ticker string) (int32, error) { + currencyPair, err := slinky.MarketPairToCurrencyPair(ticker) + if err != nil { + k.Logger(ctx).Error("Could not convert market pair to currency pair", "error", err) + return 0, err + } + + marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, currencyPair.String()) + if err != nil { + return 0, errorsmod.Wrapf( + types.ErrTickerNotFoundInMarketMap, + ticker, + ) + } + return int32(marketMapDetails.Ticker.Decimals) * -1, nil +} + // GetAllMarketParamPrices returns a slice of MarketParam, MarketPrice tuples for all markets. func (k Keeper) GetAllMarketParamPrices(ctx sdk.Context) ([]types.MarketParamPrice, error) { marketParams := k.GetAllMarketParams(ctx) diff --git a/protocol/x/prices/keeper/market_param.go b/protocol/x/prices/keeper/market_param.go index f0559bb75a..e62f92fc88 100644 --- a/protocol/x/prices/keeper/market_param.go +++ b/protocol/x/prices/keeper/market_param.go @@ -40,10 +40,6 @@ func (k Keeper) ModifyMarketParam( } // Validate update is permitted. - if updatedMarketParam.Exponent != existingParam.Exponent { - return types.MarketParam{}, - errorsmod.Wrapf(types.ErrMarketExponentCannotBeUpdated, lib.UintToString(updatedMarketParam.Id)) - } for _, market := range k.GetAllMarketParams(ctx) { if market.Pair == updatedMarketParam.Pair && market.Id != updatedMarketParam.Id { return types.MarketParam{}, errorsmod.Wrapf(types.ErrMarketParamPairAlreadyExists, updatedMarketParam.Pair) diff --git a/protocol/x/prices/keeper/market_price.go b/protocol/x/prices/keeper/market_price.go index 7d168f87c6..3cb0fdd278 100644 --- a/protocol/x/prices/keeper/market_price.go +++ b/protocol/x/prices/keeper/market_price.go @@ -174,10 +174,20 @@ func (k Keeper) GetMarketIdToValidIndexPrice( ret := make(map[uint32]types.MarketPrice) for _, marketParam := range allMarketParams { if indexPrice, exists := marketIdToValidIndexPrice[marketParam.Id]; exists { + exponent, err := k.GetExponent(ctx, marketParam.Pair) + if err != nil { + k.Logger(ctx).Error( + "failed to get exponent for market", + "market id", marketParam.Id, + "market pair", marketParam.Pair, + "error", err, + ) + continue + } ret[marketParam.Id] = types.MarketPrice{ Id: marketParam.Id, Price: indexPrice, - Exponent: marketParam.Exponent, + Exponent: exponent, } } } diff --git a/protocol/x/prices/keeper/market_test.go b/protocol/x/prices/keeper/market_test.go index b5586fabc8..dfdbb81341 100644 --- a/protocol/x/prices/keeper/market_test.go +++ b/protocol/x/prices/keeper/market_test.go @@ -11,6 +11,7 @@ import ( keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" "github.com/stretchr/testify/require" ) @@ -110,13 +111,12 @@ func TestCreateMarket_Errors(t *testing.T) { validExchangeConfigJson := `{"exchanges":[{"exchangeName":"Binance","ticker":"BTCUSDT"}]}` tests := map[string]struct { // Setup - pair string - minExchanges uint32 - minPriceChangePpm uint32 - price uint64 - marketPriceIdDoesntMatchMarketParamId bool - marketPriceExponentDoesntMatchMarketParamExponent bool - exchangeConfigJson string + pair string + minExchanges uint32 + minPriceChangePpm uint32 + price uint64 + marketPriceIdDoesntMatchMarketParamId bool + exchangeConfigJson string // Expected expectedErr string }{ @@ -163,18 +163,6 @@ func TestCreateMarket_Errors(t *testing.T) { "market param id 1 does not match market price id 2", ).Error(), }, - "Market param and price exponents don't match": { - pair: constants.BtcUsdPair, - minExchanges: uint32(2), - minPriceChangePpm: uint32(50), - price: constants.FiveBillion, - marketPriceExponentDoesntMatchMarketParamExponent: true, - exchangeConfigJson: validExchangeConfigJson, - expectedErr: errorsmod.Wrap( - types.ErrInvalidInput, - "market param 1 exponent -6 does not match market price 1 exponent -5", - ).Error(), - }, "Pair already exists": { pair: "0-0", minExchanges: uint32(2), @@ -200,11 +188,6 @@ func TestCreateMarket_Errors(t *testing.T) { marketPriceIdOffset = uint32(1) } - marketPriceExponentOffset := int32(0) - if tc.marketPriceExponentDoesntMatchMarketParamExponent { - marketPriceExponentOffset = int32(1) - } - _, err := keeper.CreateMarket( ctx, types.MarketParam{ @@ -217,7 +200,7 @@ func TestCreateMarket_Errors(t *testing.T) { }, types.MarketPrice{ Id: 1 + marketPriceIdOffset, - Exponent: int32(-6) + marketPriceExponentOffset, + Exponent: int32(-6), Price: tc.price, }, ) @@ -237,6 +220,74 @@ func TestCreateMarket_Errors(t *testing.T) { } } +func TestValidateMarketPriceExponent(t *testing.T) { + tests := []struct { + name string + marketMapDecimals uint64 + marketPriceExponent int32 + expectedError error + }{ + { + name: "Success - Market Price Exponent is negation of Market Map Decimals", + marketMapDecimals: 6, + marketPriceExponent: -6, + expectedError: nil, + }, + { + name: "Failure - Market Price Exponent is not negation of Market Map Decimals", + marketMapDecimals: 6, + marketPriceExponent: -5, + expectedError: types.ErrInvalidMarketPriceExponent, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ctx, pricesKeeper, _, _, _, _, marketMapKeeper := keepertest.PricesKeepers(t) + ctx = ctx.WithTxBytes(constants.TestTxBytes) + + // Create a market map entry for the market with the provided Decimals + currencyPair, err := slinky.MarketPairToCurrencyPair(constants.BtcUsdPair) + require.NoError(t, err) + + marketMapDetails := marketmaptypes.Market{ + Ticker: marketmaptypes.Ticker{ + CurrencyPair: currencyPair, + Decimals: uint64(tc.marketMapDecimals), + MinProviderCount: 1, + }, + ProviderConfigs: []marketmaptypes.ProviderConfig{}, + } + err = marketMapKeeper.CreateMarket(ctx, marketMapDetails) + require.NoError(t, err) + + // Create an oracle market containing MarketPrice with the provided exponent + testMarketParams := types.MarketParam{ + Id: 0, + Pair: constants.BtcUsdPair, + MinExchanges: 1, + MinPriceChangePpm: 1, + ExchangeConfigJson: "{}", + } + _, err = pricesKeeper.CreateMarket( + ctx, + testMarketParams, + types.MarketPrice{ + Id: 0, + Exponent: int32(tc.marketPriceExponent), + Price: constants.FiveBillion, + }, + ) + + if tc.expectedError != nil { + require.ErrorIs(t, err, tc.expectedError) + } else { + require.NoError(t, err) + } + }) + } +} + func TestGetAllMarketParamPrices(t *testing.T) { ctx, keeper, _, _, mockTimeProvider, _, _ := keepertest.PricesKeepers(t) mockTimeProvider.On("Now").Return(constants.TimeT) diff --git a/protocol/x/prices/keeper/msg_server_create_oracle_market.go b/protocol/x/prices/keeper/msg_server_create_oracle_market.go index 837666916c..9c326340f0 100644 --- a/protocol/x/prices/keeper/msg_server_create_oracle_market.go +++ b/protocol/x/prices/keeper/msg_server_create_oracle_market.go @@ -44,12 +44,17 @@ func (k msgServer) CreateOracleMarket( ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) + exponent, err := k.Keeper.GetExponent(ctx, msg.Params.Pair) + if err != nil { + return nil, err + } + // Use zero oracle price to create the new market. // Note that valid oracle price updates cannot be zero (checked in MsgUpdateMarketPrices.ValidateBasic), // so a zero oracle price indicates that the oracle price has never been updated. zeroMarketPrice := types.MarketPrice{ Id: msg.Params.Id, - Exponent: msg.Params.Exponent, + Exponent: exponent, Price: 0, } if _, err = k.Keeper.CreateMarket(ctx, msg.Params, zeroMarketPrice); err != nil { diff --git a/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go b/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go index 86075a0efb..ae3b4e95dd 100644 --- a/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go +++ b/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go @@ -13,13 +13,14 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" "github.com/stretchr/testify/require" ) func TestCreateOracleMarket(t *testing.T) { testMarket1 := *pricestest.GenerateMarketParamPrice( pricestest.WithId(1), - pricestest.WithPair("BTC-USD"), + pricestest.WithPair(constants.BtcUsdPair), pricestest.WithExponent(-8), // for both Param and Price pricestest.WithPriceValue(0), ) @@ -54,20 +55,16 @@ func TestCreateOracleMarket(t *testing.T) { ).Param, }, expectedMarkets: []pricestypes.MarketParamPrice{}, - expectedErr: "Pair cannot be empty", + expectedErr: "incorrectly formatted CurrencyPair", }, - "Failure: typo in exchange config json": { + "Failure: market not found in MarketMap": { setup: func(t *testing.T, ctx sdk.Context, pricesKeeper *keeper.Keeper) {}, msg: &pricestypes.MsgCreateOracleMarket{ Authority: lib.GovModuleAddress.String(), - Params: pricestest.GenerateMarketParamPrice( - pricestest.WithPair("BTC-USD"), - pricestest.WithExponent(-8), // for both Param and Price - pricestest.WithExchangeConfigJson(`{"exchanges":[{"exchangeName":"Binance"""}]}`), - ).Param, + Params: testMarket1.Param, }, + expectedErr: "Ticker not found in market map", expectedMarkets: []pricestypes.MarketParamPrice{}, - expectedErr: "ExchangeConfigJson string is not valid", }, "Failure: oracle market id already exists": { setup: func(t *testing.T, ctx sdk.Context, pricesKeeper *keeper.Keeper) { @@ -77,6 +74,14 @@ func TestCreateOracleMarket(t *testing.T) { pricesKeeper, []pricestypes.MarketParamPrice{testMarket1}, ) + keepertest.CreateMarketsInMarketMapFromParams( + t, + ctx, + pricesKeeper.MarketMapKeeper.(*marketmapkeeper.Keeper), + []pricestypes.MarketParam{pricestest.GenerateMarketParamPrice( + pricestest.WithId(1), // same id as testMarket1 + ).Param}, + ) }, msg: &pricestypes.MsgCreateOracleMarket{ Authority: lib.GovModuleAddress.String(), @@ -139,3 +144,44 @@ func TestCreateOracleMarket(t *testing.T) { }) } } + +func TestMarketPriceExponentIsFromMarketmap(t *testing.T) { + ctx, pricesKeeper, _, _, _, _, marketMapKeeper := keepertest.PricesKeepers(t) + msgServer := keeper.NewMsgServerImpl(pricesKeeper) + + // Create test market in marketmap + currencyPair, err := slinky.MarketPairToCurrencyPair(constants.BtcUsdPair) + require.NoError(t, err) + + marketMapDetails := marketmaptypes.Market{ + Ticker: marketmaptypes.Ticker{ + CurrencyPair: currencyPair, + Decimals: uint64(8), + MinProviderCount: 1, + }, + ProviderConfigs: []marketmaptypes.ProviderConfig{}, + } + err = marketMapKeeper.CreateMarket(ctx, marketMapDetails) + require.NoError(t, err) + + // Send message to create oracle market without setting exponent + // because the market price exponent is calculated from the marketmap Decimals + testMarket := pricestest.GenerateMarketParamPrice( + pricestest.WithId(1), + pricestest.WithPair(constants.BtcUsdPair), + pricestest.WithPriceValue(0), + // Do not set exponent + ) + + msg := &pricestypes.MsgCreateOracleMarket{ + Authority: lib.GovModuleAddress.String(), + Params: testMarket.Param, + } + _, err = msgServer.CreateOracleMarket(ctx, msg) + require.NoError(t, err) + + // Verify that the market price exponent matches negation of the marketmap Decimals + marketPrice, err := pricesKeeper.GetMarketPrice(ctx, 1) + require.NoError(t, err) + require.Equal(t, int32(-8), marketPrice.Exponent) +} diff --git a/protocol/x/prices/keeper/msg_server_update_market_param_test.go b/protocol/x/prices/keeper/msg_server_update_market_param_test.go index 5e837330e8..f0be3bba9a 100644 --- a/protocol/x/prices/keeper/msg_server_update_market_param_test.go +++ b/protocol/x/prices/keeper/msg_server_update_market_param_test.go @@ -122,20 +122,6 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedErr: "Invalid input", }, - "Failure: update market exponent": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: testMarketParam.Id, - Pair: testMarketParam.Pair, - Exponent: testMarketParam.Exponent + 1, // cannot be updated - MinExchanges: testMarketParam.MinExchanges, - MinPriceChangePpm: testMarketParam.MinPriceChangePpm, - ExchangeConfigJson: "{}", - }, - }, - expectedErr: "Market exponent cannot be updated", - }, "Failure: new pair name does not exist in marketmap": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), diff --git a/protocol/x/prices/module_test.go b/protocol/x/prices/module_test.go index b5c8d0dfa4..bc24360462 100644 --- a/protocol/x/prices/module_test.go +++ b/protocol/x/prices/module_test.go @@ -142,14 +142,6 @@ func TestAppModuleBasic_ValidateGenesisErr(t *testing.T) { `"exchangeConfigJson":"{}"}]}`, expectedErr: "expected the same number of market prices and market params", }, - "Bad state: Invalid price": { - genesisJson: `{"market_params":[{"pair": "DENT-USD","minExchanges":1,"minPriceChangePpm":1,` + - `"exchangeConfigJson":"{}"}],"market_prices": [{"exponent":1,"price": "0"}]}`, - expectedErr: errorsmod.Wrap( - pricestypes.ErrInvalidInput, - "market param 0 exponent 0 does not match market price 0 exponent 1", - ).Error(), - }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { diff --git a/protocol/x/prices/simulation/genesis.go b/protocol/x/prices/simulation/genesis.go index 8e04899360..b29ea23bd0 100644 --- a/protocol/x/prices/simulation/genesis.go +++ b/protocol/x/prices/simulation/genesis.go @@ -5,6 +5,7 @@ package simulation import ( "fmt" "math/rand" + "strings" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" @@ -47,8 +48,10 @@ func genMarketExponent(r *rand.Rand, isReasonableGenesis bool) int { // genMarketName return randomized market name. func genMarketName(r *rand.Rand, existingMarketNames map[string]bool) string { marketName := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 3, 6)) + "-USD" + marketName = strings.ToUpper(marketName) for existingMarketNames[marketName] { marketName = simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 3, 6)) + "-USD" + marketName = strings.ToUpper(marketName) } return marketName } diff --git a/protocol/x/prices/types/errors.go b/protocol/x/prices/types/errors.go index a549fef86e..a1235e7f65 100644 --- a/protocol/x/prices/types/errors.go +++ b/protocol/x/prices/types/errors.go @@ -30,9 +30,14 @@ var ( 206, "Market pair conversion to currency pair failed", ) - ErrTickerNotFoundInMarketMap = errorsmod.Register(ModuleName, 207, "Ticker not found in market map") - ErrMarketCouldNotBeDisabled = errorsmod.Register(ModuleName, 208, "Market could not be disabled") - ErrMarketCouldNotBeEnabled = errorsmod.Register(ModuleName, 209, "Market could not be enabled") + ErrTickerNotFoundInMarketMap = errorsmod.Register(ModuleName, 207, "Ticker not found in market map") + ErrMarketCouldNotBeDisabled = errorsmod.Register(ModuleName, 208, "Market could not be disabled") + ErrMarketCouldNotBeEnabled = errorsmod.Register(ModuleName, 209, "Market could not be enabled") + ErrInvalidMarketPriceExponent = errorsmod.Register( + ModuleName, + 210, + "Market price exponent does not match the negation of the Decimals value in the market map", + ) // 300 - 399: Price related errors. ErrIndexPriceNotAvailable = errorsmod.Register(ModuleName, 300, "Index price is not available") diff --git a/protocol/x/prices/types/market_param.pb.go b/protocol/x/prices/types/market_param.pb.go index 3be2180d28..4dbfd10c4f 100644 --- a/protocol/x/prices/types/market_param.pb.go +++ b/protocol/x/prices/types/market_param.pb.go @@ -35,7 +35,9 @@ type MarketParam struct { // For example if `Exponent == -5` then a `Value` of `1,000,000,000` // represents “$10,000`. Therefore `10 ^ Exponent` represents the smallest // price step (in dollars) that can be recorded. - Exponent int32 `protobuf:"zigzag32,3,opt,name=exponent,proto3" json:"exponent,omitempty"` + // + // Deprecated since v7.1.x. This value is now determined from the marketmap. + Exponent int32 `protobuf:"zigzag32,3,opt,name=exponent,proto3" json:"exponent,omitempty"` // Deprecated: Do not use. // The minimum number of exchanges that should be reporting a live price for // a price update to be considered valid. MinExchanges uint32 `protobuf:"varint,4,opt,name=min_exchanges,json=minExchanges,proto3" json:"min_exchanges,omitempty"` @@ -94,6 +96,7 @@ func (m *MarketParam) GetPair() string { return "" } +// Deprecated: Do not use. func (m *MarketParam) GetExponent() int32 { if m != nil { return m.Exponent @@ -131,25 +134,25 @@ func init() { } var fileDescriptor_39174a2dba54f799 = []byte{ - // 284 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0x3f, 0x4b, 0xc4, 0x30, - 0x1c, 0x86, 0x2f, 0xf5, 0x3c, 0x34, 0x7a, 0xc2, 0xc5, 0x1b, 0x82, 0x43, 0x28, 0x0a, 0xd2, 0xc5, - 0x56, 0xd0, 0xc1, 0xd9, 0xc3, 0x45, 0x10, 0x4a, 0x47, 0x97, 0x90, 0x4b, 0x63, 0x1b, 0x35, 0x7f, - 0x68, 0xa3, 0xf4, 0xbe, 0x85, 0x1f, 0xcb, 0xf1, 0x16, 0xc1, 0x51, 0xda, 0x2f, 0x22, 0xcd, 0xd1, - 0x43, 0xb7, 0xe4, 0x7d, 0x1e, 0x7e, 0xbc, 0xbc, 0xf0, 0x3c, 0x5f, 0xe5, 0x8d, 0xad, 0x8c, 0x33, - 0xdc, 0xbc, 0x26, 0xb6, 0x92, 0x5c, 0xd4, 0x89, 0x62, 0xd5, 0x8b, 0x70, 0xd4, 0xb2, 0x8a, 0xa9, - 0xd8, 0x43, 0x74, 0xfc, 0xd7, 0x8b, 0x37, 0xde, 0xe9, 0x17, 0x80, 0x07, 0x0f, 0xde, 0x4d, 0x7b, - 0x15, 0x1d, 0xc1, 0x40, 0xe6, 0x18, 0x84, 0x20, 0x9a, 0x66, 0x81, 0xcc, 0x11, 0x82, 0x63, 0xcb, - 0x64, 0x85, 0x83, 0x10, 0x44, 0xfb, 0x99, 0x7f, 0xa3, 0x13, 0xb8, 0x27, 0x1a, 0x6b, 0xb4, 0xd0, - 0x0e, 0xef, 0x84, 0x20, 0x9a, 0x65, 0xdb, 0x3f, 0x3a, 0x83, 0x53, 0x25, 0x35, 0x15, 0x0d, 0x2f, - 0x99, 0x2e, 0x44, 0x8d, 0xc7, 0xfe, 0xd4, 0xa1, 0x92, 0xfa, 0x6e, 0xc8, 0x50, 0x02, 0xe7, 0xbd, - 0xe4, 0x2b, 0xd0, 0x4d, 0x48, 0xad, 0x55, 0x78, 0xd7, 0xbb, 0x33, 0x25, 0x75, 0xda, 0xa3, 0x85, - 0x27, 0xa9, 0x55, 0xe8, 0x12, 0xce, 0x87, 0x8b, 0x94, 0x1b, 0xfd, 0x24, 0x0b, 0xfa, 0x5c, 0x1b, - 0x8d, 0x27, 0xbe, 0x15, 0x1a, 0xd8, 0xc2, 0xa3, 0xfb, 0xda, 0xe8, 0xdb, 0xec, 0xb3, 0x25, 0x60, - 0xdd, 0x12, 0xf0, 0xd3, 0x12, 0xf0, 0xd1, 0x91, 0xd1, 0xba, 0x23, 0xa3, 0xef, 0x8e, 0x8c, 0x1e, - 0x6f, 0x0a, 0xe9, 0xca, 0xb7, 0x65, 0xcc, 0x8d, 0x4a, 0xfe, 0x2d, 0xf7, 0x7e, 0x7d, 0xc1, 0x4b, - 0x26, 0x75, 0xb2, 0x4d, 0x9a, 0x61, 0x4d, 0xb7, 0xb2, 0xa2, 0x5e, 0x4e, 0x3c, 0xb8, 0xfa, 0x0d, - 0x00, 0x00, 0xff, 0xff, 0x98, 0x21, 0x4b, 0x29, 0x71, 0x01, 0x00, 0x00, + // 285 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0x4f, 0x4b, 0xc3, 0x30, + 0x14, 0xc0, 0x97, 0x3a, 0x87, 0x46, 0x27, 0x2c, 0xee, 0x90, 0x53, 0x28, 0x0a, 0xd2, 0x8b, 0xad, + 0xa0, 0x07, 0xcf, 0x1b, 0x5e, 0x04, 0xa1, 0xf4, 0xe8, 0x25, 0x64, 0x69, 0x6c, 0xa3, 0xe6, 0x0f, + 0x6d, 0x94, 0xee, 0x5b, 0xf8, 0xb1, 0x3c, 0xee, 0xa8, 0x37, 0x69, 0xbf, 0x88, 0x34, 0xa3, 0x43, + 0x6f, 0x8f, 0xdf, 0xef, 0xc7, 0xe3, 0xf1, 0xe0, 0x45, 0xbe, 0xce, 0x1b, 0x5b, 0x19, 0x67, 0xb8, + 0x79, 0x4d, 0x6c, 0x25, 0xb9, 0xa8, 0x13, 0xc5, 0xaa, 0x17, 0xe1, 0xa8, 0x65, 0x15, 0x53, 0xb1, + 0x97, 0xe8, 0xf4, 0x6f, 0x17, 0x6f, 0xbb, 0xb3, 0x6f, 0x00, 0x8f, 0x1e, 0x7c, 0x9b, 0xf6, 0x29, + 0x3a, 0x81, 0x81, 0xcc, 0x31, 0x08, 0x41, 0x34, 0xcd, 0x02, 0x99, 0x23, 0x04, 0xc7, 0x96, 0xc9, + 0x0a, 0x07, 0x21, 0x88, 0x0e, 0x33, 0x3f, 0x23, 0x02, 0x0f, 0x44, 0x63, 0x8d, 0x16, 0xda, 0xe1, + 0xbd, 0x10, 0x44, 0xb3, 0x45, 0x80, 0x41, 0xb6, 0x63, 0xe8, 0x1c, 0x4e, 0x95, 0xd4, 0x54, 0x34, + 0xbc, 0x64, 0xba, 0x10, 0x35, 0x1e, 0xfb, 0x75, 0xc7, 0x4a, 0xea, 0xbb, 0x81, 0xa1, 0x04, 0xce, + 0xfb, 0xc8, 0x9f, 0x41, 0xb7, 0x90, 0x5a, 0xab, 0xf0, 0xbe, 0x6f, 0x67, 0x4a, 0xea, 0xb4, 0x57, + 0x4b, 0x6f, 0x52, 0xab, 0xd0, 0x15, 0x9c, 0x0f, 0x1b, 0x29, 0x37, 0xfa, 0x49, 0x16, 0xf4, 0xb9, + 0x36, 0x1a, 0x4f, 0xfc, 0x65, 0x68, 0x70, 0x4b, 0xaf, 0xee, 0x6b, 0xa3, 0x17, 0xd9, 0x67, 0x4b, + 0xc0, 0xa6, 0x25, 0xe0, 0xa7, 0x25, 0xe0, 0xa3, 0x23, 0xa3, 0x4d, 0x47, 0x46, 0x5f, 0x1d, 0x19, + 0x3d, 0xde, 0x16, 0xd2, 0x95, 0x6f, 0xab, 0x98, 0x1b, 0x95, 0xfc, 0xfb, 0xde, 0xfb, 0xcd, 0x25, + 0x2f, 0x99, 0xd4, 0xc9, 0x8e, 0x34, 0xc3, 0x47, 0xdd, 0xda, 0x8a, 0x7a, 0x35, 0xf1, 0xe2, 0xfa, + 0x37, 0x00, 0x00, 0xff, 0xff, 0x7c, 0xfb, 0xf1, 0xbc, 0x75, 0x01, 0x00, 0x00, } func (m *MarketParam) Marshal() (dAtA []byte, err error) { diff --git a/protocol/x/prices/types/market_price.go b/protocol/x/prices/types/market_price.go index c88e7192f4..e90a9a0cc7 100644 --- a/protocol/x/prices/types/market_price.go +++ b/protocol/x/prices/types/market_price.go @@ -14,15 +14,5 @@ func (mp *MarketPrice) ValidateFromParam(marketParam MarketParam) error { mp.Id, ) } - if marketParam.Exponent != mp.Exponent { - return errorsmod.Wrapf( - ErrInvalidInput, - "market param %d exponent %d does not match market price %d exponent %d", - marketParam.Id, - marketParam.Exponent, - mp.Id, - mp.Exponent, - ) - } return nil } diff --git a/protocol/x/prices/types/market_price.pb.go b/protocol/x/prices/types/market_price.pb.go index 9da0bdef89..a86b2f60ed 100644 --- a/protocol/x/prices/types/market_price.pb.go +++ b/protocol/x/prices/types/market_price.pb.go @@ -28,6 +28,9 @@ type MarketPrice struct { Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // Static value. The exponent of the price. See the comment on the duplicate // MarketParam field for more information. + // + // As of v7.1.x, this value is determined from the marketmap instead of + // needing to match the MarketParam field. Exponent int32 `protobuf:"zigzag32,2,opt,name=exponent,proto3" json:"exponent,omitempty"` // The variable value that is updated by oracle price updates. `0` if it has // never been updated, `>0` otherwise. diff --git a/protocol/x/prices/types/types.go b/protocol/x/prices/types/types.go index ba32185e93..1940a39ae6 100644 --- a/protocol/x/prices/types/types.go +++ b/protocol/x/prices/types/types.go @@ -31,6 +31,7 @@ type PricesKeeper interface { GetAllMarketParams(ctx sdk.Context) (marketParams []MarketParam) GetMarketPrice(ctx sdk.Context, id uint32) (marketPrice MarketPrice, err error) GetAllMarketPrices(ctx sdk.Context) (marketPrices []MarketPrice) + GetExponent(ctx sdk.Context, ticker string) (exponent int32, err error) HasAuthority(authority string) bool // Validation related. From 0fb623268e3a590bd601285850ab52e1e5263bcf Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 2 Oct 2024 11:12:07 -0400 Subject: [PATCH 062/120] Fix issue with flaky candle test (#2430) --- .../__tests__/lib/candles-generator.test.ts | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index cd014d3eaf..34935d6c53 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -471,6 +471,210 @@ describe('candleHelper', () => { expectTimingStats(); }); +<<<<<<< HEAD +======= + it('Updates previous candle orderBookMidPriceClose if startTime is past candle resolution', async () => { + // Create existing candles + const existingPrice: string = '7000'; + const startingOpenInterest: string = '200'; + const baseTokenVolume: string = '10'; + const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); + const orderbookMidPriceClose = '7500'; + const orderbookMidPriceOpen = '8000'; + // Set candle start time to be far in the past to ensure all candles are new + const startTime: IsoString = helpers.calculateNormalizedCandleStartTime( + testConstants.createdDateTime.minus({ minutes: 100 }), + CandleResolution.ONE_MINUTE, + ).toISO(); + + await Promise.all( + _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { + return CandleTable.create({ + startedAt: startTime, + ticker: testConstants.defaultPerpetualMarket.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume, + usdVolume, + trades: existingTrades, + startingOpenInterest, + orderbookMidPriceClose, + orderbookMidPriceOpen, + }); + }), + ); + await startCandleCache(); + + await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + + // Add two trades for BTC-USD market + const publisher: KafkaPublisher = new KafkaPublisher(); + publisher.addEvents([ + defaultTradeKafkaEvent, + defaultTradeKafkaEvent2, + ]); + + // Create new candles, with trades + await runUpdateCandles(publisher); + + // Verify previous candles have orderbookMidPriceClose updated + const previousExpectedCandles: CandleFromDatabase[] = _.map( + Object.values(CandleResolution), + (resolution: CandleResolution) => { + return { + id: CandleTable.uuid(startTime, defaultCandle.ticker, resolution), + startedAt: startTime, + ticker: defaultCandle.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume, + usdVolume, + trades: existingTrades, + startingOpenInterest, + orderbookMidPriceClose: '10005', + orderbookMidPriceOpen, + }; + }, + ); + await verifyCandlesInPostgres(previousExpectedCandles); + + // Verify new candles were created + const expectedCandles: CandleFromDatabase[] = _.map( + Object.values(CandleResolution), + (resolution: CandleResolution) => { + const currentStartedAt: IsoString = helpers.calculateNormalizedCandleStartTime( + testConstants.createdDateTime, + resolution, + ).toISO(); + + return { + id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), + startedAt: currentStartedAt, + ticker: defaultCandle.ticker, + resolution, + low: '10000', + high: defaultPrice2, + open: '10000', + close: defaultPrice2, + baseTokenVolume: '20', + usdVolume: '250000', + trades: 2, + startingOpenInterest: '0', + orderbookMidPriceClose: '10005', + orderbookMidPriceOpen: '10005', + }; + }, + ); + await verifyCandlesInPostgres(expectedCandles); + await validateCandlesCache(); + expectTimingStats(); + }); + + it('creates an empty candle and updates the previous candle orderBookMidPriceClose if startTime is past candle resolution', async () => { + // Create existing candles + const existingPrice: string = '7000'; + const startingOpenInterest: string = '200'; + const baseTokenVolume: string = '10'; + const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); + const orderbookMidPriceClose = '7500'; + const orderbookMidPriceOpen = '8000'; + // Set candle start time to be far in the past to ensure all candles are new + const startTime: IsoString = helpers.calculateNormalizedCandleStartTime( + testConstants.createdDateTime.minus({ minutes: 100 }), + CandleResolution.ONE_MINUTE, + ).toISO(); + + await Promise.all( + _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { + return CandleTable.create({ + startedAt: startTime, + ticker: testConstants.defaultPerpetualMarket.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume, + usdVolume, + trades: existingTrades, + startingOpenInterest, + orderbookMidPriceClose, + orderbookMidPriceOpen, + }); + }), + ); + await startCandleCache(); + + await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + + const publisher: KafkaPublisher = new KafkaPublisher(); + publisher.addEvents([]); + + // Create new candles, without trades + await runUpdateCandles(publisher); + + // Verify previous candles have orderbookMidPriceClose updated + const previousExpectedCandles: CandleFromDatabase[] = _.map( + Object.values(CandleResolution), + (resolution: CandleResolution) => { + return { + id: CandleTable.uuid(startTime, defaultCandle.ticker, resolution), + startedAt: startTime, + ticker: defaultCandle.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume, + usdVolume, + trades: existingTrades, + startingOpenInterest, + orderbookMidPriceClose: '10005', + orderbookMidPriceOpen, + }; + }, + ); + await verifyCandlesInPostgres(previousExpectedCandles); + + // Verify new empty candle was created + const expectedCandles: CandleFromDatabase[] = _.map( + Object.values(CandleResolution), + (resolution: CandleResolution) => { + const currentStartedAt: IsoString = helpers.calculateNormalizedCandleStartTime( + testConstants.createdDateTime, + resolution, + ).toISO(); + + return { + id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), + startedAt: currentStartedAt, + ticker: defaultCandle.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume: '0', + usdVolume: '0', + trades: 0, + startingOpenInterest: '0', + orderbookMidPriceClose: '10005', + orderbookMidPriceOpen: '10005', + }; + }, + ); + await verifyCandlesInPostgres(expectedCandles); + + }); + +>>>>>>> 672169be7 (Fix issue with flaky candle test (#2430)) it('successfully creates an orderbook price map for each market', async () => { await Promise.all([ OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), From ca4a23c7524429672469ca05986ec34358446dfd Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:26:10 -0400 Subject: [PATCH 063/120] =?UTF-8?q?[CT-1202]=20logic=20to=20handle=20unaut?= =?UTF-8?q?horized=20maker=20orders=20when=20authenticato=E2=80=A6=20(#241?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/app/app.go | 1 + protocol/mocks/MemClobKeeper.go | 20 ++++++- protocol/testutil/keeper/accountplus.go | 8 +-- protocol/testutil/keeper/clob.go | 13 ++++- protocol/testutil/keeper/listing.go | 9 ++- protocol/testutil/memclob/keeper.go | 4 ++ .../x/accountplus/keeper/authenticators.go | 58 +++++++++++++++++++ protocol/x/accountplus/types/errors.go | 5 ++ protocol/x/clob/abci_test.go | 11 +++- protocol/x/clob/keeper/authenticators.go | 21 +++++++ protocol/x/clob/keeper/keeper.go | 3 + protocol/x/clob/keeper/liquidations_test.go | 22 ++++++- protocol/x/clob/keeper/orders_test.go | 19 +++++- protocol/x/clob/memclob/memclob.go | 18 ++++++ protocol/x/clob/types/expected_keepers.go | 4 ++ protocol/x/clob/types/mem_clob_keeper.go | 1 + .../x/clob/types/operations_to_propose.go | 24 ++++++++ 17 files changed, 229 insertions(+), 12 deletions(-) create mode 100644 protocol/x/clob/keeper/authenticators.go diff --git a/protocol/app/app.go b/protocol/app/app.go index 08b46bc042..9796322d21 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1139,6 +1139,7 @@ func New( app.StatsKeeper, app.RewardsKeeper, app.AffiliatesKeeper, + app.AccountPlusKeeper, app.IndexerEventManager, app.FullNodeStreamingManager, txConfig.TxDecoder(), diff --git a/protocol/mocks/MemClobKeeper.go b/protocol/mocks/MemClobKeeper.go index 5d8d68d42f..032e175d12 100644 --- a/protocol/mocks/MemClobKeeper.go +++ b/protocol/mocks/MemClobKeeper.go @@ -288,6 +288,24 @@ func (_m *MemClobKeeper) Logger(ctx types.Context) log.Logger { return r0 } +// MaybeValidateAuthenticators provides a mock function with given fields: ctx, txBytes +func (_m *MemClobKeeper) MaybeValidateAuthenticators(ctx types.Context, txBytes []byte) error { + ret := _m.Called(ctx, txBytes) + + if len(ret) == 0 { + panic("no return value specified for MaybeValidateAuthenticators") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, []byte) error); ok { + r0 = rf(ctx, txBytes) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // OffsetSubaccountPerpetualPosition provides a mock function with given fields: ctx, liquidatedSubaccountId, perpetualId, deltaQuantumsTotal, isFinalSettlement func (_m *MemClobKeeper) OffsetSubaccountPerpetualPosition(ctx types.Context, liquidatedSubaccountId subaccountstypes.SubaccountId, perpetualId uint32, deltaQuantumsTotal *big.Int, isFinalSettlement bool) ([]clobtypes.MatchPerpetualDeleveraging_Fill, *big.Int) { ret := _m.Called(ctx, liquidatedSubaccountId, perpetualId, deltaQuantumsTotal, isFinalSettlement) @@ -415,7 +433,7 @@ func (_m *MemClobKeeper) ReplayPlaceOrder(ctx types.Context, msg *clobtypes.MsgP return r0, r1, r2, r3 } -// SendOrderbookFillUpdate provides a mock function with given fields: ctx, orderbookFills +// SendOrderbookFillUpdate provides a mock function with given fields: ctx, orderbookFill func (_m *MemClobKeeper) SendOrderbookFillUpdate(ctx types.Context, orderbookFill clobtypes.StreamOrderbookFill) { _m.Called(ctx, orderbookFill) } diff --git a/protocol/testutil/keeper/accountplus.go b/protocol/testutil/keeper/accountplus.go index d518aace3f..8b90b3be0b 100644 --- a/protocol/testutil/keeper/accountplus.go +++ b/protocol/testutil/keeper/accountplus.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/dydxprotocol/v4-chain/protocol/lib" - "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,7 +16,7 @@ import ( keeper "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper" ) -func TimestampNonceKeepers(t testing.TB) ( +func AccountPlusKeepers(t testing.TB) ( ctx sdk.Context, keeper *keeper.Keeper, storeKey storetypes.StoreKey, @@ -32,7 +32,7 @@ func TimestampNonceKeepers(t testing.TB) ( ) []GenesisInitializer { // Define necessary keepers here for unit tests keeper, storeKey, mockTimeProvider = - createTimestampNonceKeeper(stateStore, db, cdc) + createAccountPlusKeeper(stateStore, db, cdc) return []GenesisInitializer{keeper} }, @@ -41,7 +41,7 @@ func TimestampNonceKeepers(t testing.TB) ( return ctx, keeper, storeKey, mockTimeProvider } -func createTimestampNonceKeeper( +func createAccountPlusKeeper( stateStore storetypes.CommitMultiStore, db *dbm.MemDB, cdc *codec.ProtoCodec, diff --git a/protocol/testutil/keeper/clob.go b/protocol/testutil/keeper/clob.go index eddbabd9bf..0e1b1ba1e9 100644 --- a/protocol/testutil/keeper/clob.go +++ b/protocol/testutil/keeper/clob.go @@ -17,6 +17,7 @@ import ( streaming "github.com/dydxprotocol/v4-chain/protocol/streaming" clobtest "github.com/dydxprotocol/v4-chain/protocol/testutil/clob" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + accountpluskeeper "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper" affiliateskeeper "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/keeper" asskeeper "github.com/dydxprotocol/v4-chain/protocol/x/assets/keeper" blocktimekeeper "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/keeper" @@ -51,6 +52,7 @@ type ClobKeepersTestContext struct { SubaccountsKeeper *subkeeper.Keeper AffiliatesKeeper *affiliateskeeper.Keeper VaultKeeper *vaultkeeper.Keeper + AccountPlusKeeper *accountpluskeeper.Keeper StoreKey storetypes.StoreKey MemKey storetypes.StoreKey Cdc *codec.ProtoCodec @@ -91,7 +93,13 @@ func NewClobKeepersTestContextWithUninitializedMemStore( stateStore, db, cdc, - registry) + registry, + ) + ks.AccountPlusKeeper, _, _ = createAccountPlusKeeper( + stateStore, + db, + cdc, + ) stakingKeeper, _ := createStakingKeeper( stateStore, @@ -191,6 +199,7 @@ func NewClobKeepersTestContextWithUninitializedMemStore( ks.AffiliatesKeeper, ks.SubaccountsKeeper, revShareKeeper, + ks.AccountPlusKeeper, indexerEventManager, indexerEventsTransientStoreKey, ) @@ -231,6 +240,7 @@ func createClobKeeper( affiliatesKeeper types.AffiliatesKeeper, saKeeper *subkeeper.Keeper, revShareKeeper types.RevShareKeeper, + accountplusKeeper types.AccountPlusKeeper, indexerEventManager indexer_manager.IndexerEventManager, indexerEventsTransientStoreKey storetypes.StoreKey, ) (*keeper.Keeper, storetypes.StoreKey, storetypes.StoreKey) { @@ -262,6 +272,7 @@ func createClobKeeper( statsKeeper, rewardsKeeper, affiliatesKeeper, + accountplusKeeper, indexerEventManager, streaming.NewNoopGrpcStreamingManager(), constants.TestEncodingCfg.TxConfig.TxDecoder(), diff --git a/protocol/testutil/keeper/listing.go b/protocol/testutil/keeper/listing.go index 824eb50ef5..49f181ecbb 100644 --- a/protocol/testutil/keeper/listing.go +++ b/protocol/testutil/keeper/listing.go @@ -56,7 +56,13 @@ func ListingKeepers( stateStore, db, cdc, - registry) + registry, + ) + accountPlusKeeper, _, _ := createAccountPlusKeeper( + stateStore, + db, + cdc, + ) bankKeeper, _ = createBankKeeper(stateStore, db, cdc, accountsKeeper) stakingKeeper, _ := createStakingKeeper( stateStore, @@ -154,6 +160,7 @@ func ListingKeepers( affiliatesKeeper, subaccountsKeeper, revShareKeeper, + accountPlusKeeper, indexerEventManager, transientStoreKey, ) diff --git a/protocol/testutil/memclob/keeper.go b/protocol/testutil/memclob/keeper.go index 376f6fb30a..3b4282e42e 100644 --- a/protocol/testutil/memclob/keeper.go +++ b/protocol/testutil/memclob/keeper.go @@ -528,3 +528,7 @@ func (f *FakeMemClobKeeper) AddOrderToOrderbookSubaccountUpdatesCheck( ) satypes.UpdateResult { return satypes.Success } + +func (f *FakeMemClobKeeper) MaybeValidateAuthenticators(ctx sdk.Context, txBytes []byte) error { + return nil +} diff --git a/protocol/x/accountplus/keeper/authenticators.go b/protocol/x/accountplus/keeper/authenticators.go index fc2ac0c013..71d8b9aede 100644 --- a/protocol/x/accountplus/keeper/authenticators.go +++ b/protocol/x/accountplus/keeper/authenticators.go @@ -10,11 +10,69 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" gogotypes "github.com/cosmos/gogoproto/types" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) +// MaybeValidateAuthenticators checks if the transaction has authenticators specified and if so, +// validates them. It returns an error if the authenticators are not valid or removed from state. +func (k Keeper) MaybeValidateAuthenticators(ctx sdk.Context, tx sdk.Tx) error { + // Check if the tx had authenticator specified. + specified, txOptions := lib.HasSelectedAuthenticatorTxExtensionSpecified(tx, k.cdc) + if !specified { + return nil + } + + // The tx had authenticators specified. + // First make sure smart account flow is enabled. + if active := k.GetIsSmartAccountActive(ctx); !active { + return types.ErrSmartAccountNotActive + } + + // Make sure txn is a SigVerifiableTx and get signers from the tx. + sigVerifiableTx, ok := tx.(authsigning.SigVerifiableTx) + if !ok { + return errors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") + } + + signers, err := sigVerifiableTx.GetSigners() + if err != nil { + return err + } + + if len(signers) != 1 { + return errors.Wrap(types.ErrTxnHasMultipleSigners, "only one signer is allowed") + } + + account := sdk.AccAddress(signers[0]) + + // Retrieve the selected authenticators from the extension and make sure they are valid, i.e. they + // are registered and not removed from state. + // + // Note that we only verify the existence of the authenticators here without actually + // runnning them. This is because all current authenticators are stateless and do not read/modify any states. + selectedAuthenticators := txOptions.GetSelectedAuthenticators() + for _, authenticatorId := range selectedAuthenticators { + _, err := k.GetInitializedAuthenticatorForAccount( + ctx, + account, + authenticatorId, + ) + if err != nil { + return errors.Wrapf( + err, + "selected authenticator (%s, %d) is not registered or removed from state", + account.String(), + authenticatorId, + ) + } + } + return nil +} + // AddAuthenticator adds an authenticator to an account, this function is used to add multiple // authenticators such as SignatureVerifications and AllOfs func (k Keeper) AddAuthenticator( diff --git a/protocol/x/accountplus/types/errors.go b/protocol/x/accountplus/types/errors.go index 861e5925e0..9307876c66 100644 --- a/protocol/x/accountplus/types/errors.go +++ b/protocol/x/accountplus/types/errors.go @@ -28,4 +28,9 @@ var ( 5, "Error initializing authenticator", ) + ErrTxnHasMultipleSigners = errorsmod.Register( + ModuleName, + 6, + "The transaction has multiple signers", + ) ) diff --git a/protocol/x/clob/abci_test.go b/protocol/x/clob/abci_test.go index 661b8bd4e0..992eb84f37 100644 --- a/protocol/x/clob/abci_test.go +++ b/protocol/x/clob/abci_test.go @@ -1211,8 +1211,15 @@ func TestPrepareCheckState(t *testing.T) { case *types.Operation_ShortTermOrderPlacement: order := operation.GetShortTermOrderPlacement() tempCtx, writeCache := setupCtx.CacheContext() - tempCtx = tempCtx.WithTxBytes(order.Order.GetOrderHash().ToBytes()) - _, _, err := ks.ClobKeeper.PlaceShortTermOrder( + + txBuilder := constants.TestEncodingCfg.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(operation.GetShortTermOrderPlacement()) + require.NoError(t, err) + bytes, err := constants.TestEncodingCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + tempCtx = tempCtx.WithTxBytes(bytes) + + _, _, err = ks.ClobKeeper.PlaceShortTermOrder( tempCtx, order, ) diff --git a/protocol/x/clob/keeper/authenticators.go b/protocol/x/clob/keeper/authenticators.go new file mode 100644 index 0000000000..0c78f6478d --- /dev/null +++ b/protocol/x/clob/keeper/authenticators.go @@ -0,0 +1,21 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// MaybeValidateAuthenticators checks if the transaction has authenticators specified and if so, +// validates them. It returns an error if the authenticators are not valid or removed from state. +func (k Keeper) MaybeValidateAuthenticators(ctx sdk.Context, txBytes []byte) error { + // Decode the tx from the tx bytes. + tx, err := k.txDecoder(txBytes) + if err != nil { + return err + } + + // Perform a light-weight validation of the authenticators via the accountplus module. + // + // Note that alternatively we could have been calling the ante handler directly on this transaction, + // but there are some deadlock issues that are non-trivial to resolve. + return k.accountPlusKeeper.MaybeValidateAuthenticators(ctx, tx) +} diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index f49eb61271..dbdfdbc0c2 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -44,6 +44,7 @@ type ( rewardsKeeper types.RewardsKeeper affiliatesKeeper types.AffiliatesKeeper revshareKeeper types.RevShareKeeper + accountPlusKeeper types.AccountPlusKeeper indexerEventManager indexer_manager.IndexerEventManager streamingManager streamingtypes.FullNodeStreamingManager @@ -88,6 +89,7 @@ func NewKeeper( statsKeeper types.StatsKeeper, rewardsKeeper types.RewardsKeeper, affiliatesKeeper types.AffiliatesKeeper, + accountPlusKeeper types.AccountPlusKeeper, indexerEventManager indexer_manager.IndexerEventManager, streamingManager streamingtypes.FullNodeStreamingManager, txDecoder sdk.TxDecoder, @@ -114,6 +116,7 @@ func NewKeeper( statsKeeper: statsKeeper, rewardsKeeper: rewardsKeeper, affiliatesKeeper: affiliatesKeeper, + accountPlusKeeper: accountPlusKeeper, indexerEventManager: indexerEventManager, streamingManager: streamingManager, memStoreInitialized: &atomic.Bool{}, // False by default. diff --git a/protocol/x/clob/keeper/liquidations_test.go b/protocol/x/clob/keeper/liquidations_test.go index 89809421b6..cd8ffe61fe 100644 --- a/protocol/x/clob/keeper/liquidations_test.go +++ b/protocol/x/clob/keeper/liquidations_test.go @@ -352,7 +352,16 @@ func TestPlacePerpetualLiquidation(t *testing.T) { // Create all existing orders. for _, order := range tc.existingOrders { - _, _, err := ks.ClobKeeper.PlaceShortTermOrder(ctx, &types.MsgPlaceOrder{Order: order}) + msg := &types.MsgPlaceOrder{Order: order} + + txBuilder := constants.TestEncodingCfg.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msg) + require.NoError(t, err) + bytes, err := constants.TestEncodingCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + ctx = ctx.WithTxBytes(bytes) + + _, _, err = ks.ClobKeeper.PlaceShortTermOrder(ctx, msg) require.NoError(t, err) } @@ -1306,7 +1315,16 @@ func TestPlacePerpetualLiquidation_PreexistingLiquidation(t *testing.T) { require.NoError(t, err) } else { order := matchableOrder.MustGetOrder() - _, _, err := ks.ClobKeeper.PlaceShortTermOrder(ctx, &types.MsgPlaceOrder{Order: order.MustGetOrder()}) + msg := &types.MsgPlaceOrder{Order: order} + + txBuilder := constants.TestEncodingCfg.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msg) + require.NoError(t, err) + bytes, err := constants.TestEncodingCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + ctx = ctx.WithTxBytes(bytes) + + _, _, err = ks.ClobKeeper.PlaceShortTermOrder(ctx, msg) require.NoError(t, err) } } diff --git a/protocol/x/clob/keeper/orders_test.go b/protocol/x/clob/keeper/orders_test.go index b7138d71ab..e8a68b6828 100644 --- a/protocol/x/clob/keeper/orders_test.go +++ b/protocol/x/clob/keeper/orders_test.go @@ -623,7 +623,16 @@ func TestPlaceShortTermOrder(t *testing.T) { // Create all existing orders. for _, order := range tc.existingOrders { - _, _, err := ks.ClobKeeper.PlaceShortTermOrder(ctx, &types.MsgPlaceOrder{Order: order}) + msg := &types.MsgPlaceOrder{Order: order} + + txBuilder := constants.TestEncodingCfg.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msg) + require.NoError(t, err) + bytes, err := constants.TestEncodingCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + ctx = ctx.WithTxBytes(bytes) + + _, _, err = ks.ClobKeeper.PlaceShortTermOrder(ctx, msg) require.NoError(t, err) } @@ -632,6 +641,14 @@ func TestPlaceShortTermOrder(t *testing.T) { ctx.MultiStore().SetTracer(traceDecoder) msg := &types.MsgPlaceOrder{Order: tc.order} + + txBuilder := constants.TestEncodingCfg.TxConfig.NewTxBuilder() + err = txBuilder.SetMsgs(msg) + require.NoError(t, err) + bytes, err := constants.TestEncodingCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + ctx = ctx.WithTxBytes(bytes) + orderSizeOptimisticallyFilledFromMatching, orderStatus, err := ks.ClobKeeper.PlaceShortTermOrder(ctx, msg) diff --git a/protocol/x/clob/memclob/memclob.go b/protocol/x/clob/memclob/memclob.go index db541650c3..d0de165e08 100644 --- a/protocol/x/clob/memclob/memclob.go +++ b/protocol/x/clob/memclob/memclob.go @@ -1624,6 +1624,24 @@ func (m *MemClobPriceTimePriority) mustPerformTakerOrderMatching( continue } + // Perform a lightweight check on maker orders that use the new smart account authentication flow. + // Note that this only applies to short term orders since short term orders go through the ante + // handlers one more time during `DeliverTx`. + if makerOrder.Order.IsShortTermOrder() { + txBytes := m.operationsToPropose.MustGetShortTermOrderTxBytes(makerOrder.Order) + err := m.clobKeeper.MaybeValidateAuthenticators(ctx, txBytes) + if err != nil { + makerOrdersToRemove = append( + makerOrdersToRemove, + OrderWithRemovalReason{ + Order: makerOrder.Order, + RemovalReason: types.OrderRemoval_REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED, + }, + ) + continue + } + } + makerRemainingSize, makerHasRemainingSize := m.GetOrderRemainingAmount(ctx, makerOrder.Order) if !makerHasRemainingSize { panic(fmt.Sprintf("mustPerformTakerOrderMatching: maker order has no remaining amount %v", makerOrder.Order)) diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index 872daf2905..05e25e2521 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -184,3 +184,7 @@ type RevShareKeeper interface { type AffiliatesKeeper interface { GetAffiliateWhitelistMap(ctx sdk.Context) (map[string]uint32, error) } + +type AccountPlusKeeper interface { + MaybeValidateAuthenticators(ctx sdk.Context, tx sdk.Tx) error +} diff --git a/protocol/x/clob/types/mem_clob_keeper.go b/protocol/x/clob/types/mem_clob_keeper.go index 6e25cadf35..bd396a6c16 100644 --- a/protocol/x/clob/types/mem_clob_keeper.go +++ b/protocol/x/clob/types/mem_clob_keeper.go @@ -115,4 +115,5 @@ type MemClobKeeper interface { subaccountId satypes.SubaccountId, order PendingOpenOrder, ) satypes.UpdateResult + MaybeValidateAuthenticators(ctx sdk.Context, txBytes []byte) error } diff --git a/protocol/x/clob/types/operations_to_propose.go b/protocol/x/clob/types/operations_to_propose.go index e135987178..997197c47b 100644 --- a/protocol/x/clob/types/operations_to_propose.go +++ b/protocol/x/clob/types/operations_to_propose.go @@ -475,3 +475,27 @@ func (o *OperationsToPropose) GetOperationsToPropose() []OperationRaw { return operationRaws } + +// MustGetShortTermOrderTxBytes returns the `ShortTermOrderHashToTxBytes` for a short term order. +// This function will panic for any of the following: +// - the order is not a short term order. +// - the order hash is not present in `ShortTermOrderHashToTxBytes` +func (o *OperationsToPropose) MustGetShortTermOrderTxBytes( + order Order, +) (txBytes []byte) { + order.OrderId.MustBeShortTermOrder() + + orderHash := order.GetOrderHash() + bytes, exists := o.ShortTermOrderHashToTxBytes[orderHash] + if !exists { + panic( + fmt.Sprintf( + "MustGetShortTermOrderTxBytes: Order (%s) does not exist in "+ + "`ShortTermOrderHashToTxBytes`.", + order.GetOrderTextString(), + ), + ) + } + + return bytes +} From 3fa58d71beed67aaf5b4be8483d561a627c4cba1 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:43:00 -0400 Subject: [PATCH 064/120] Update large cap params in genesis (#2431) --- protocol/scripts/genesis/sample_pregenesis.json | 2 +- protocol/testing/genesis.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index e8f7131930..34c0e49637 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -2985,7 +2985,7 @@ { "id": 0, "impact_notional": 10000000000, - "initial_margin_ppm": 50000, + "initial_margin_ppm": 20000, "maintenance_fraction_ppm": 600000, "name": "Large-Cap", "open_interest_lower_cap": 0, diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index 69dab93c04..5a428f3e28 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -137,7 +137,7 @@ function edit_genesis() { dasel put -t json -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].id' -v '0' dasel put -t string -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].name' -v 'Large-Cap' - dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].initial_margin_ppm' -v '50000' # 5% + dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].initial_margin_ppm' -v '20000' # 2% dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].maintenance_fraction_ppm' -v '600000' # 60% of IM dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].impact_notional' -v '10000000000' # 10_000 USDC (500 USDC / 5%) dasel put -t int -f "$GENESIS" '.app_state.perpetuals.liquidity_tiers.[0].open_interest_lower_cap' -v '0' # OIMF doesn't apply to Large-Cap From 69435802787fbb47b0a7bb54ea9986079ecf2249 Mon Sep 17 00:00:00 2001 From: Alex | Skip Date: Wed, 2 Oct 2024 13:57:57 -0400 Subject: [PATCH 065/120] feat: upgrade to connect/v2 (#2419) --- protocol/app/ante/market_update.go | 7 +- protocol/app/ante/market_update_test.go | 4 +- protocol/app/ante/replay_protection.go | 2 +- protocol/app/app.go | 26 +- protocol/app/app_test.go | 2 +- protocol/app/basic_manager/basic_manager.go | 2 +- protocol/app/module_accounts.go | 2 +- protocol/app/module_accounts_test.go | 2 +- protocol/app/msgs/all_msgs.go | 26 +- protocol/app/msgs/normal_msgs.go | 30 +- protocol/app/msgs/normal_msgs_test.go | 26 +- protocol/app/prepare/prepare_proposal.go | 2 +- protocol/app/prepare/prepare_proposal_test.go | 14 +- .../prices/slinky_price_update_generator.go | 8 +- .../slinky_price_update_generator_test.go | 14 +- .../process/slinky_market_price_decoder.go | 2 +- .../slinky_market_price_decoder_test.go | 2 +- protocol/app/upgrades/v6.0.0/constants.go | 4 +- protocol/app/upgrades/v6.0.0/upgrade.go | 8 +- .../app/vote_extensions/expected_keepers.go | 5 +- .../vote_extensions/extend_vote_handler.go | 5 +- protocol/app/vote_extensions/oracle_client.go | 2 +- .../app/vote_extensions/oracle_client_test.go | 2 +- protocol/cmd/dydxprotocold/cmd/config.go | 2 +- protocol/daemons/flags/flags.go | 2 +- .../client/price_function/exchange_error.go | 3 +- protocol/daemons/slinky/client/client.go | 2 +- protocol/daemons/slinky/client/client_test.go | 2 +- .../slinky/client/market_pair_fetcher.go | 2 +- .../slinky/client/market_pair_fetcher_test.go | 2 +- .../daemons/slinky/client/price_fetcher.go | 6 +- .../slinky/client/price_fetcher_test.go | 2 +- protocol/go.mod | 185 +++++----- protocol/go.sum | 348 +++++++++--------- protocol/lib/marketmap/utils.go | 6 +- protocol/lib/marketmap/utils_test.go | 4 +- protocol/lib/slinky/utils.go | 2 +- protocol/lib/slinky/utils_test.go | 2 +- protocol/mocks/AnteDecorator.go | 2 +- protocol/mocks/AppOptions.go | 2 +- protocol/mocks/BankKeeper.go | 2 +- protocol/mocks/BridgeKeeper.go | 2 +- protocol/mocks/BridgeQueryClient.go | 2 +- protocol/mocks/BridgeServiceClient.go | 2 +- protocol/mocks/CacheMultiStore.go | 2 +- protocol/mocks/ClobKeeper.go | 2 +- protocol/mocks/Configurator.go | 2 +- protocol/mocks/DelayMsgKeeper.go | 1 + protocol/mocks/EthClient.go | 2 +- protocol/mocks/ExchangeConfigUpdater.go | 2 +- protocol/mocks/ExchangeQueryHandler.go | 2 +- protocol/mocks/ExchangeToMarketPrices.go | 2 +- protocol/mocks/ExtendVoteHandler.go | 2 +- protocol/mocks/FileHandler.go | 2 +- protocol/mocks/GrpcClient.go | 2 +- protocol/mocks/GrpcServer.go | 2 +- protocol/mocks/HealthCheckable.go | 2 +- protocol/mocks/IndexerEventManager.go | 2 +- protocol/mocks/IndexerMessageSender.go | 2 +- protocol/mocks/Logger.go | 2 +- protocol/mocks/Makefile | 4 +- protocol/mocks/MarketPairFetcher.go | 4 +- protocol/mocks/MemClob.go | 2 +- protocol/mocks/MemClobKeeper.go | 2 +- protocol/mocks/MsgRouter.go | 2 +- protocol/mocks/MultiStore.go | 2 +- protocol/mocks/OracleClient.go | 4 +- protocol/mocks/PerpetualsClobKeeper.go | 2 +- protocol/mocks/PerpetualsKeeper.go | 2 +- protocol/mocks/PrepareBridgeKeeper.go | 2 +- protocol/mocks/PrepareClobKeeper.go | 2 +- protocol/mocks/PreparePerpetualsKeeper.go | 2 +- .../mocks/PriceFeedMutableMarketConfigs.go | 2 +- protocol/mocks/PriceFetcher.go | 2 +- protocol/mocks/PriceUpdateGenerator.go | 2 +- protocol/mocks/PricesKeeper.go | 42 ++- protocol/mocks/ProcessBridgeKeeper.go | 2 +- protocol/mocks/ProcessClobKeeper.go | 2 +- protocol/mocks/ProcessPerpetualKeeper.go | 2 +- protocol/mocks/ProcessStakingKeeper.go | 2 +- protocol/mocks/QueryClient.go | 2 +- protocol/mocks/QueryServer.go | 2 +- protocol/mocks/RequestHandler.go | 2 +- protocol/mocks/SendingKeeper.go | 2 +- protocol/mocks/Server.go | 2 +- protocol/mocks/SubaccountsKeeper.go | 2 +- protocol/mocks/TimeProvider.go | 2 +- protocol/mocks/TxBuilder.go | 2 +- protocol/mocks/TxConfig.go | 2 +- protocol/mocks/UpdateMarketPriceTxDecoder.go | 2 +- protocol/mocks/VaultKeeper.go | 2 +- .../testing/e2e/gov/add_new_market_test.go | 2 +- protocol/testing/e2e/gov/perpetuals_test.go | 4 +- protocol/testing/e2e/gov/prices_test.go | 2 +- protocol/testutil/app/app.go | 2 +- protocol/testutil/constants/marketmap.go | 4 +- protocol/testutil/keeper/clob.go | 2 +- protocol/testutil/keeper/listing.go | 2 +- protocol/testutil/keeper/marketmap.go | 4 +- protocol/testutil/keeper/perpetuals.go | 2 +- protocol/testutil/keeper/prices.go | 2 +- protocol/testutil/network/network.go | 2 +- protocol/testutil/prices/cli/util.go | 2 +- protocol/x/clob/keeper/process_operations.go | 2 +- protocol/x/clob/module_test.go | 2 +- protocol/x/delaymsg/keeper/delayed_message.go | 4 +- protocol/x/listing/keeper/listing.go | 20 +- protocol/x/listing/keeper/listing_test.go | 6 +- .../msg_create_market_permissionless_test.go | 6 +- protocol/x/listing/types/expected_keepers.go | 9 +- protocol/x/prices/keeper/market.go | 31 +- protocol/x/prices/keeper/market_param.go | 6 +- protocol/x/prices/keeper/market_param_test.go | 6 +- protocol/x/prices/keeper/market_test.go | 5 +- .../msg_server_create_oracle_market_test.go | 4 +- protocol/x/prices/keeper/slinky_adapter.go | 38 +- .../x/prices/keeper/slinky_adapter_test.go | 2 +- protocol/x/prices/module_test.go | 2 +- protocol/x/prices/simulation/genesis.go | 2 +- protocol/x/prices/types/expected_keepers.go | 10 +- protocol/x/prices/types/types.go | 14 +- protocol/x/vault/keeper/orders.go | 2 +- protocol/x/vest/types/vest_entry.go | 10 +- 123 files changed, 584 insertions(+), 545 deletions(-) diff --git a/protocol/app/ante/market_update.go b/protocol/app/ante/market_update.go index 9575f4da49..6b4ae40bcf 100644 --- a/protocol/app/ante/market_update.go +++ b/protocol/app/ante/market_update.go @@ -1,14 +1,15 @@ package ante import ( + "context" "errors" "fmt" - slinkytypes "github.com/skip-mev/slinky/pkg/types" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - mmtypes "github.com/skip-mev/slinky/x/marketmap/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + mmtypes "github.com/skip-mev/connect/v2/x/marketmap/types" slinkylibs "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" perpetualstypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" @@ -19,7 +20,7 @@ var ErrRestrictedMarketUpdates = errors.New("cannot call MsgUpdateMarkets or Msg "on a restricted market") type MarketMapKeeper interface { - GetAllMarkets(ctx sdk.Context) (map[string]mmtypes.Market, error) + GetAllMarkets(ctx context.Context) (map[string]mmtypes.Market, error) } var ( diff --git a/protocol/app/ante/market_update_test.go b/protocol/app/ante/market_update_test.go index d97cb91fab..28a03ab7b1 100644 --- a/protocol/app/ante/market_update_test.go +++ b/protocol/app/ante/market_update_test.go @@ -14,8 +14,8 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/skip-mev/slinky/pkg/types" - mmtypes "github.com/skip-mev/slinky/x/marketmap/types" + "github.com/skip-mev/connect/v2/pkg/types" + mmtypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" "github.com/dydxprotocol/v4-chain/protocol/app/ante" diff --git a/protocol/app/ante/replay_protection.go b/protocol/app/ante/replay_protection.go index d2fb6a25bd..0514e62e6e 100644 --- a/protocol/app/ante/replay_protection.go +++ b/protocol/app/ante/replay_protection.go @@ -86,7 +86,7 @@ func (rpd ReplayProtectionDecorator) AnteHandle( 1, []gometrics.Label{metrics.GetLabelForIntValue(metrics.ExecMode, int(ctx.ExecMode()))}, ) - return ctx, errorsmod.Wrapf(sdkerrors.ErrWrongSequence, err.Error()) + return ctx, errorsmod.Wrap(sdkerrors.ErrWrongSequence, err.Error()) } telemetry.IncrCounterWithLabels( []string{metrics.TimestampNonce, metrics.Valid, metrics.Count}, diff --git a/protocol/app/app.go b/protocol/app/app.go index 9796322d21..5b4e38955a 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -198,9 +198,9 @@ import ( vestmodule "github.com/dydxprotocol/v4-chain/protocol/x/vest" vestmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/vest/keeper" vestmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/vest/types" - marketmapmodule "github.com/skip-mev/slinky/x/marketmap" - marketmapmodulekeeper "github.com/skip-mev/slinky/x/marketmap/keeper" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapmodule "github.com/skip-mev/connect/v2/x/marketmap" + marketmapmodulekeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" // IBC ica "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" @@ -225,16 +225,16 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/indexer/msgsender" // Slinky - slinkyproposals "github.com/skip-mev/slinky/abci/proposals" - "github.com/skip-mev/slinky/abci/strategies/aggregator" - compression "github.com/skip-mev/slinky/abci/strategies/codec" - "github.com/skip-mev/slinky/abci/strategies/currencypair" - "github.com/skip-mev/slinky/abci/ve" - oracleconfig "github.com/skip-mev/slinky/oracle/config" - "github.com/skip-mev/slinky/pkg/math/voteweighted" - oracleclient "github.com/skip-mev/slinky/service/clients/oracle" - servicemetrics "github.com/skip-mev/slinky/service/metrics" - promserver "github.com/skip-mev/slinky/service/servers/prometheus" + slinkyproposals "github.com/skip-mev/connect/v2/abci/proposals" + "github.com/skip-mev/connect/v2/abci/strategies/aggregator" + compression "github.com/skip-mev/connect/v2/abci/strategies/codec" + "github.com/skip-mev/connect/v2/abci/strategies/currencypair" + "github.com/skip-mev/connect/v2/abci/ve" + oracleconfig "github.com/skip-mev/connect/v2/oracle/config" + "github.com/skip-mev/connect/v2/pkg/math/voteweighted" + oracleclient "github.com/skip-mev/connect/v2/service/clients/oracle" + servicemetrics "github.com/skip-mev/connect/v2/service/metrics" + promserver "github.com/skip-mev/connect/v2/service/servers/prometheus" // Full Node Streaming streaming "github.com/dydxprotocol/v4-chain/protocol/streaming" diff --git a/protocol/app/app_test.go b/protocol/app/app_test.go index db4bba13a3..a0130d2167 100644 --- a/protocol/app/app_test.go +++ b/protocol/app/app_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - marketmapmodule "github.com/skip-mev/slinky/x/marketmap" + marketmapmodule "github.com/skip-mev/connect/v2/x/marketmap" evidencemodule "cosmossdk.io/x/evidence" feegrantmodule "cosmossdk.io/x/feegrant/module" diff --git a/protocol/app/basic_manager/basic_manager.go b/protocol/app/basic_manager/basic_manager.go index c4d17251ca..dd9122a5a7 100644 --- a/protocol/app/basic_manager/basic_manager.go +++ b/protocol/app/basic_manager/basic_manager.go @@ -42,7 +42,7 @@ import ( subaccountsmodule "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts" vaultmodule "github.com/dydxprotocol/v4-chain/protocol/x/vault" vestmodule "github.com/dydxprotocol/v4-chain/protocol/x/vest" - marketmapmodule "github.com/skip-mev/slinky/x/marketmap" + marketmapmodule "github.com/skip-mev/connect/v2/x/marketmap" ica "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" "github.com/cosmos/ibc-go/v8/modules/apps/transfer" diff --git a/protocol/app/module_accounts.go b/protocol/app/module_accounts.go index c699218c8e..920e5ebd4c 100644 --- a/protocol/app/module_accounts.go +++ b/protocol/app/module_accounts.go @@ -15,7 +15,7 @@ import ( satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaultmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" vestmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/vest/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" "golang.org/x/exp/maps" ) diff --git a/protocol/app/module_accounts_test.go b/protocol/app/module_accounts_test.go index 097d379943..6585a4c8c7 100644 --- a/protocol/app/module_accounts_test.go +++ b/protocol/app/module_accounts_test.go @@ -18,7 +18,7 @@ import ( satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaultmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" vestmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/vest/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) func TestModuleAccountsToAddresses(t *testing.T) { diff --git a/protocol/app/msgs/all_msgs.go b/protocol/app/msgs/all_msgs.go index d09a39cccd..2369ef1056 100644 --- a/protocol/app/msgs/all_msgs.go +++ b/protocol/app/msgs/all_msgs.go @@ -8,6 +8,20 @@ var ( // AllTypeMessages is a list of all messages and types that are used in the app. // This list comes from the app's `InterfaceRegistry`. AllTypeMessages = map[string]struct{}{ + // connect marketmap messages + "/connect.marketmap.v2.MsgCreateMarkets": {}, + "/connect.marketmap.v2.MsgCreateMarketsResponse": {}, + "/connect.marketmap.v2.MsgParams": {}, + "/connect.marketmap.v2.MsgParamsResponse": {}, + "/connect.marketmap.v2.MsgRemoveMarkets": {}, + "/connect.marketmap.v2.MsgRemoveMarketsResponse": {}, + "/connect.marketmap.v2.MsgRemoveMarketAuthorities": {}, + "/connect.marketmap.v2.MsgRemoveMarketAuthoritiesResponse": {}, + "/connect.marketmap.v2.MsgUpdateMarkets": {}, + "/connect.marketmap.v2.MsgUpdateMarketsResponse": {}, + "/connect.marketmap.v2.MsgUpsertMarkets": {}, + "/connect.marketmap.v2.MsgUpsertMarketsResponse": {}, + // auth "/cosmos.auth.v1beta1.BaseAccount": {}, "/cosmos.auth.v1beta1.ModuleAccount": {}, @@ -389,18 +403,6 @@ var ( "/ibc.applications.interchain_accounts.controller.v1.MsgUpdateParamsResponse": {}, "/ibc.applications.interchain_accounts.host.v1.MsgUpdateParams": {}, "/ibc.applications.interchain_accounts.host.v1.MsgUpdateParamsResponse": {}, - - // slinky marketmap messages - "/slinky.marketmap.v1.MsgCreateMarkets": {}, - "/slinky.marketmap.v1.MsgCreateMarketsResponse": {}, - "/slinky.marketmap.v1.MsgParams": {}, - "/slinky.marketmap.v1.MsgParamsResponse": {}, - "/slinky.marketmap.v1.MsgRemoveMarketAuthorities": {}, - "/slinky.marketmap.v1.MsgRemoveMarketAuthoritiesResponse": {}, - "/slinky.marketmap.v1.MsgUpdateMarkets": {}, - "/slinky.marketmap.v1.MsgUpdateMarketsResponse": {}, - "/slinky.marketmap.v1.MsgUpsertMarkets": {}, - "/slinky.marketmap.v1.MsgUpsertMarketsResponse": {}, } // DisallowMsgs are messages that cannot be externally submitted. diff --git a/protocol/app/msgs/normal_msgs.go b/protocol/app/msgs/normal_msgs.go index 2990258712..6b4dfb18a5 100644 --- a/protocol/app/msgs/normal_msgs.go +++ b/protocol/app/msgs/normal_msgs.go @@ -23,12 +23,12 @@ import ( listing "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" sending "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" vault "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) var ( // NormalMsgs are messages that can be submitted by external users. - NormalMsgs = lib.MergeAllMapsMustHaveDistinctKeys(NormalMsgsDefault, NormalMsgsDydxCustom, NormalMsgsSlinky) + NormalMsgs = lib.MergeAllMapsMustHaveDistinctKeys(NormalMsgsDefault, NormalMsgsDydxCustom, NormalMsgsConnect) // Default modules NormalMsgsDefault = map[string]sdk.Msg{ @@ -267,17 +267,19 @@ var ( "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse": nil, } - NormalMsgsSlinky = map[string]sdk.Msg{ - // slinky marketmap messages - "/slinky.marketmap.v1.MsgCreateMarkets": &marketmapmoduletypes.MsgCreateMarkets{}, - "/slinky.marketmap.v1.MsgCreateMarketsResponse": nil, - "/slinky.marketmap.v1.MsgParams": &marketmapmoduletypes.MsgParams{}, - "/slinky.marketmap.v1.MsgParamsResponse": nil, - "/slinky.marketmap.v1.MsgRemoveMarketAuthorities": &marketmapmoduletypes.MsgRemoveMarketAuthorities{}, - "/slinky.marketmap.v1.MsgRemoveMarketAuthoritiesResponse": nil, - "/slinky.marketmap.v1.MsgUpdateMarkets": &marketmapmoduletypes.MsgUpdateMarkets{}, - "/slinky.marketmap.v1.MsgUpdateMarketsResponse": nil, - "/slinky.marketmap.v1.MsgUpsertMarkets": &marketmapmoduletypes.MsgUpsertMarkets{}, - "/slinky.marketmap.v1.MsgUpsertMarketsResponse": nil, + NormalMsgsConnect = map[string]sdk.Msg{ + // connect marketmap messages + "/connect.marketmap.v2.MsgCreateMarkets": &marketmapmoduletypes.MsgCreateMarkets{}, + "/connect.marketmap.v2.MsgCreateMarketsResponse": nil, + "/connect.marketmap.v2.MsgParams": &marketmapmoduletypes.MsgParams{}, + "/connect.marketmap.v2.MsgParamsResponse": nil, + "/connect.marketmap.v2.MsgRemoveMarketAuthorities": &marketmapmoduletypes.MsgRemoveMarketAuthorities{}, + "/connect.marketmap.v2.MsgRemoveMarketAuthoritiesResponse": nil, + "/connect.marketmap.v2.MsgRemoveMarkets": &marketmapmoduletypes.MsgRemoveMarkets{}, + "/connect.marketmap.v2.MsgRemoveMarketsResponse": nil, + "/connect.marketmap.v2.MsgUpdateMarkets": &marketmapmoduletypes.MsgUpdateMarkets{}, + "/connect.marketmap.v2.MsgUpdateMarketsResponse": nil, + "/connect.marketmap.v2.MsgUpsertMarkets": &marketmapmoduletypes.MsgUpsertMarkets{}, + "/connect.marketmap.v2.MsgUpsertMarketsResponse": nil, } ) diff --git a/protocol/app/msgs/normal_msgs_test.go b/protocol/app/msgs/normal_msgs_test.go index 2ae0015db5..759fa3c605 100644 --- a/protocol/app/msgs/normal_msgs_test.go +++ b/protocol/app/msgs/normal_msgs_test.go @@ -11,6 +11,20 @@ import ( func TestNormalMsgs_Key(t *testing.T) { expectedMsgs := []string{ + // connect marketmap messages + "/connect.marketmap.v2.MsgCreateMarkets", + "/connect.marketmap.v2.MsgCreateMarketsResponse", + "/connect.marketmap.v2.MsgParams", + "/connect.marketmap.v2.MsgParamsResponse", + "/connect.marketmap.v2.MsgRemoveMarketAuthorities", + "/connect.marketmap.v2.MsgRemoveMarketAuthoritiesResponse", + "/connect.marketmap.v2.MsgRemoveMarkets", + "/connect.marketmap.v2.MsgRemoveMarketsResponse", + "/connect.marketmap.v2.MsgUpdateMarkets", + "/connect.marketmap.v2.MsgUpdateMarketsResponse", + "/connect.marketmap.v2.MsgUpsertMarkets", + "/connect.marketmap.v2.MsgUpsertMarketsResponse", + // auth "/cosmos.auth.v1beta1.BaseAccount", "/cosmos.auth.v1beta1.ModuleAccount", @@ -239,18 +253,6 @@ func TestNormalMsgs_Key(t *testing.T) { "/ibc.lightclients.tendermint.v1.ConsensusState", "/ibc.lightclients.tendermint.v1.Header", "/ibc.lightclients.tendermint.v1.Misbehaviour", - - // slinky marketmap messages - "/slinky.marketmap.v1.MsgCreateMarkets", - "/slinky.marketmap.v1.MsgCreateMarketsResponse", - "/slinky.marketmap.v1.MsgParams", - "/slinky.marketmap.v1.MsgParamsResponse", - "/slinky.marketmap.v1.MsgRemoveMarketAuthorities", - "/slinky.marketmap.v1.MsgRemoveMarketAuthoritiesResponse", - "/slinky.marketmap.v1.MsgUpdateMarkets", - "/slinky.marketmap.v1.MsgUpdateMarketsResponse", - "/slinky.marketmap.v1.MsgUpsertMarkets", - "/slinky.marketmap.v1.MsgUpsertMarketsResponse", } require.Equal(t, expectedMsgs, lib.GetSortedKeys[sort.StringSlice](msgs.NormalMsgs)) diff --git a/protocol/app/prepare/prepare_proposal.go b/protocol/app/prepare/prepare_proposal.go index ce7dd8751d..3cb527aaa1 100644 --- a/protocol/app/prepare/prepare_proposal.go +++ b/protocol/app/prepare/prepare_proposal.go @@ -14,7 +14,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/app/prepare/prices" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" pricetypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - "github.com/skip-mev/slinky/abci/ve" + "github.com/skip-mev/connect/v2/abci/ve" ) var ( diff --git a/protocol/app/prepare/prepare_proposal_test.go b/protocol/app/prepare/prepare_proposal_test.go index 367da90302..ab0af2917f 100644 --- a/protocol/app/prepare/prepare_proposal_test.go +++ b/protocol/app/prepare/prepare_proposal_test.go @@ -21,13 +21,13 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - "github.com/skip-mev/slinky/abci/strategies/aggregator" - aggregatormock "github.com/skip-mev/slinky/abci/strategies/aggregator/mocks" - "github.com/skip-mev/slinky/abci/strategies/codec" - strategymock "github.com/skip-mev/slinky/abci/strategies/currencypair/mocks" - slinkytestutils "github.com/skip-mev/slinky/abci/testutils" - vetypes "github.com/skip-mev/slinky/abci/ve/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" + "github.com/skip-mev/connect/v2/abci/strategies/aggregator" + aggregatormock "github.com/skip-mev/connect/v2/abci/strategies/aggregator/mocks" + "github.com/skip-mev/connect/v2/abci/strategies/codec" + strategymock "github.com/skip-mev/connect/v2/abci/strategies/currencypair/mocks" + slinkytestutils "github.com/skip-mev/connect/v2/abci/testutils" + vetypes "github.com/skip-mev/connect/v2/abci/ve/types" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) diff --git a/protocol/app/prepare/prices/slinky_price_update_generator.go b/protocol/app/prepare/prices/slinky_price_update_generator.go index 4754d836c7..153ee1c2cb 100644 --- a/protocol/app/prepare/prices/slinky_price_update_generator.go +++ b/protocol/app/prepare/prices/slinky_price_update_generator.go @@ -5,10 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - "github.com/skip-mev/slinky/abci/strategies/aggregator" - "github.com/skip-mev/slinky/abci/strategies/codec" - "github.com/skip-mev/slinky/abci/strategies/currencypair" - "github.com/skip-mev/slinky/abci/ve" + "github.com/skip-mev/connect/v2/abci/strategies/aggregator" + "github.com/skip-mev/connect/v2/abci/strategies/codec" + "github.com/skip-mev/connect/v2/abci/strategies/currencypair" + "github.com/skip-mev/connect/v2/abci/ve" ) // SlinkyPriceUpdateGenerator is an implementation of the PriceUpdateGenerator interface. This implementation diff --git a/protocol/app/prepare/prices/slinky_price_update_generator_test.go b/protocol/app/prepare/prices/slinky_price_update_generator_test.go index 6769e9ad47..fab534fc87 100644 --- a/protocol/app/prepare/prices/slinky_price_update_generator_test.go +++ b/protocol/app/prepare/prices/slinky_price_update_generator_test.go @@ -5,13 +5,13 @@ import ( cmtabci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dydxprotocol/v4-chain/protocol/app/prepare/prices" - "github.com/skip-mev/slinky/abci/strategies/aggregator" - aggregatormock "github.com/skip-mev/slinky/abci/strategies/aggregator/mocks" - codecmock "github.com/skip-mev/slinky/abci/strategies/codec/mocks" - strategymock "github.com/skip-mev/slinky/abci/strategies/currencypair/mocks" - "github.com/skip-mev/slinky/abci/testutils" - vetypes "github.com/skip-mev/slinky/abci/ve/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" + "github.com/skip-mev/connect/v2/abci/strategies/aggregator" + aggregatormock "github.com/skip-mev/connect/v2/abci/strategies/aggregator/mocks" + codecmock "github.com/skip-mev/connect/v2/abci/strategies/codec/mocks" + strategymock "github.com/skip-mev/connect/v2/abci/strategies/currencypair/mocks" + "github.com/skip-mev/connect/v2/abci/testutils" + vetypes "github.com/skip-mev/connect/v2/abci/ve/types" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" "github.com/stretchr/testify/suite" "math/big" "testing" diff --git a/protocol/app/process/slinky_market_price_decoder.go b/protocol/app/process/slinky_market_price_decoder.go index 53d1e2fa3b..07e05caee2 100644 --- a/protocol/app/process/slinky_market_price_decoder.go +++ b/protocol/app/process/slinky_market_price_decoder.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/slinky/abci/ve" + "github.com/skip-mev/connect/v2/abci/ve" "github.com/dydxprotocol/v4-chain/protocol/app/constants" "github.com/dydxprotocol/v4-chain/protocol/app/prepare/prices" diff --git a/protocol/app/process/slinky_market_price_decoder_test.go b/protocol/app/process/slinky_market_price_decoder_test.go index 6880737cce..2ed6358ab2 100644 --- a/protocol/app/process/slinky_market_price_decoder_test.go +++ b/protocol/app/process/slinky_market_price_decoder_test.go @@ -5,7 +5,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/slinky/abci/testutils" + "github.com/skip-mev/connect/v2/abci/testutils" "github.com/stretchr/testify/suite" "github.com/dydxprotocol/v4-chain/protocol/app/constants" diff --git a/protocol/app/upgrades/v6.0.0/constants.go b/protocol/app/upgrades/v6.0.0/constants.go index 59b3253405..7b7b9c99fb 100644 --- a/protocol/app/upgrades/v6.0.0/constants.go +++ b/protocol/app/upgrades/v6.0.0/constants.go @@ -2,8 +2,8 @@ package v_6_0_0 import ( store "cosmossdk.io/store/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/dydxprotocol/v4-chain/protocol/app/upgrades" accountplustypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" diff --git a/protocol/app/upgrades/v6.0.0/upgrade.go b/protocol/app/upgrades/v6.0.0/upgrade.go index fca255a4d3..d05748b6d2 100644 --- a/protocol/app/upgrades/v6.0.0/upgrade.go +++ b/protocol/app/upgrades/v6.0.0/upgrade.go @@ -14,10 +14,10 @@ import ( revsharetypes "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" - "github.com/skip-mev/slinky/providers/apis/dydx" - dydxtypes "github.com/skip-mev/slinky/providers/apis/dydx/types" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + "github.com/skip-mev/connect/v2/providers/apis/dydx" + dydxtypes "github.com/skip-mev/connect/v2/providers/apis/dydx/types" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" diff --git a/protocol/app/vote_extensions/expected_keepers.go b/protocol/app/vote_extensions/expected_keepers.go index b472a201e9..fdba16a985 100644 --- a/protocol/app/vote_extensions/expected_keepers.go +++ b/protocol/app/vote_extensions/expected_keepers.go @@ -1,15 +1,16 @@ package vote_extensions import ( + "context" sdk "github.com/cosmos/cosmos-sdk/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" ) // PricesKeeper is the expected interface for the x/price keeper used by the vote extension handlers type PricesKeeper interface { - GetCurrencyPairFromID(ctx sdk.Context, id uint64) (cp oracletypes.CurrencyPair, found bool) + GetCurrencyPairFromID(ctx context.Context, id uint64) (cp oracletypes.CurrencyPair, found bool) GetValidMarketPriceUpdates(ctx sdk.Context) *pricestypes.MsgUpdateMarketPrices UpdateMarketPrices( ctx sdk.Context, diff --git a/protocol/app/vote_extensions/extend_vote_handler.go b/protocol/app/vote_extensions/extend_vote_handler.go index fefde4a5ed..16eb3b28d6 100644 --- a/protocol/app/vote_extensions/extend_vote_handler.go +++ b/protocol/app/vote_extensions/extend_vote_handler.go @@ -2,7 +2,7 @@ package vote_extensions import ( "fmt" - slinkytypes "github.com/skip-mev/slinky/pkg/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" "math/big" cometabci "github.com/cometbft/cometbft/abci/types" @@ -38,7 +38,8 @@ func (n NoopPriceApplier) GetPricesForValidator(_ sdk.ConsAddress) map[slinkytyp // latest available market prices // 4. Calling the Slinky ExtendVoteHandler to handle the rest of ExtendVote // -// See https://github.com/skip-mev/slinky/blob/a5b1d3d3a2723e4746b5d588c512d7cc052dc0ff/abci/ve/vote_extension.go#L77 +// See +// https://github.com/skip-mev/connect/v2/blob/a5b1d3d3a2723e4746b5d588c512d7cc052dc0ff/abci/ve/vote_extension.go#L77 // for the Slinky ExtendVoteHandler logic. func (e *ExtendVoteHandler) ExtendVoteHandler() sdk.ExtendVoteHandler { return func(ctx sdk.Context, req *cometabci.RequestExtendVote) (resp *cometabci.ResponseExtendVote, err error) { diff --git a/protocol/app/vote_extensions/oracle_client.go b/protocol/app/vote_extensions/oracle_client.go index 07fc0e647f..42a1f0bd01 100644 --- a/protocol/app/vote_extensions/oracle_client.go +++ b/protocol/app/vote_extensions/oracle_client.go @@ -7,7 +7,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - oracleservicetypes "github.com/skip-mev/slinky/service/servers/oracle/types" + oracleservicetypes "github.com/skip-mev/connect/v2/service/servers/oracle/types" "google.golang.org/grpc" ) diff --git a/protocol/app/vote_extensions/oracle_client_test.go b/protocol/app/vote_extensions/oracle_client_test.go index 0bf1a3ed4f..c69751939c 100644 --- a/protocol/app/vote_extensions/oracle_client_test.go +++ b/protocol/app/vote_extensions/oracle_client_test.go @@ -6,7 +6,7 @@ import ( "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/protocol/cmd/dydxprotocold/cmd/config.go b/protocol/cmd/dydxprotocold/cmd/config.go index 56429a5762..e0e1d43c0a 100644 --- a/protocol/cmd/dydxprotocold/cmd/config.go +++ b/protocol/cmd/dydxprotocold/cmd/config.go @@ -7,7 +7,7 @@ import ( serverconfig "github.com/cosmos/cosmos-sdk/server/config" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" - oracleconfig "github.com/skip-mev/slinky/oracle/config" + oracleconfig "github.com/skip-mev/connect/v2/oracle/config" ) const ( diff --git a/protocol/daemons/flags/flags.go b/protocol/daemons/flags/flags.go index 939e32f68d..7eb7d263b6 100644 --- a/protocol/daemons/flags/flags.go +++ b/protocol/daemons/flags/flags.go @@ -4,7 +4,7 @@ import ( "time" servertypes "github.com/cosmos/cosmos-sdk/server/types" - oracleconfig "github.com/skip-mev/slinky/oracle/config" + oracleconfig "github.com/skip-mev/connect/v2/oracle/config" "github.com/spf13/cast" "github.com/spf13/cobra" ) diff --git a/protocol/daemons/pricefeed/client/price_function/exchange_error.go b/protocol/daemons/pricefeed/client/price_function/exchange_error.go index 2bbce0aad2..cc605465d9 100644 --- a/protocol/daemons/pricefeed/client/price_function/exchange_error.go +++ b/protocol/daemons/pricefeed/client/price_function/exchange_error.go @@ -2,6 +2,7 @@ package price_function import ( "fmt" + "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/types" ) @@ -35,6 +36,6 @@ func (e *ExchangeErrorImpl) GetExchangeId() types.ExchangeId { func NewExchangeError(exchangeId types.ExchangeId, msg string) ExchangeError { return &ExchangeErrorImpl{ exchangeId: exchangeId, - err: fmt.Errorf(msg), + err: fmt.Errorf("%s", msg), } } diff --git a/protocol/daemons/slinky/client/client.go b/protocol/daemons/slinky/client/client.go index 0f37a1a676..1d02337002 100644 --- a/protocol/daemons/slinky/client/client.go +++ b/protocol/daemons/slinky/client/client.go @@ -9,7 +9,7 @@ import ( "cosmossdk.io/log" - oracleclient "github.com/skip-mev/slinky/service/clients/oracle" + oracleclient "github.com/skip-mev/connect/v2/service/clients/oracle" appflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" "github.com/dydxprotocol/v4-chain/protocol/daemons/flags" diff --git a/protocol/daemons/slinky/client/client_test.go b/protocol/daemons/slinky/client/client_test.go index 7f39835918..a256619b98 100644 --- a/protocol/daemons/slinky/client/client_test.go +++ b/protocol/daemons/slinky/client/client_test.go @@ -7,7 +7,7 @@ import ( "time" "cosmossdk.io/log" - "github.com/skip-mev/slinky/service/servers/oracle/types" + "github.com/skip-mev/connect/v2/service/servers/oracle/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc" diff --git a/protocol/daemons/slinky/client/market_pair_fetcher.go b/protocol/daemons/slinky/client/market_pair_fetcher.go index bfcc42e311..0fbc676144 100644 --- a/protocol/daemons/slinky/client/market_pair_fetcher.go +++ b/protocol/daemons/slinky/client/market_pair_fetcher.go @@ -14,7 +14,7 @@ import ( daemontypes "github.com/dydxprotocol/v4-chain/protocol/daemons/types" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" pricetypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" ) // MarketPairFetcher is a lightweight process run in a goroutine by the slinky client. diff --git a/protocol/daemons/slinky/client/market_pair_fetcher_test.go b/protocol/daemons/slinky/client/market_pair_fetcher_test.go index 34cacb3967..a7fc2235b5 100644 --- a/protocol/daemons/slinky/client/market_pair_fetcher_test.go +++ b/protocol/daemons/slinky/client/market_pair_fetcher_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - slinkytypes "github.com/skip-mev/slinky/pkg/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" "github.com/dydxprotocol/v4-chain/protocol/daemons/slinky/client" "github.com/dydxprotocol/v4-chain/protocol/mocks" diff --git a/protocol/daemons/slinky/client/price_fetcher.go b/protocol/daemons/slinky/client/price_fetcher.go index e8f72465de..06709fd9ba 100644 --- a/protocol/daemons/slinky/client/price_fetcher.go +++ b/protocol/daemons/slinky/client/price_fetcher.go @@ -5,9 +5,9 @@ import ( "strconv" "cosmossdk.io/log" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - oracleclient "github.com/skip-mev/slinky/service/clients/oracle" - "github.com/skip-mev/slinky/service/servers/oracle/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + oracleclient "github.com/skip-mev/connect/v2/service/clients/oracle" + "github.com/skip-mev/connect/v2/service/servers/oracle/types" "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/api" pricefeedtypes "github.com/dydxprotocol/v4-chain/protocol/daemons/server/types/pricefeed" diff --git a/protocol/daemons/slinky/client/price_fetcher_test.go b/protocol/daemons/slinky/client/price_fetcher_test.go index 4a9d7f21d8..7781dae7ef 100644 --- a/protocol/daemons/slinky/client/price_fetcher_test.go +++ b/protocol/daemons/slinky/client/price_fetcher_test.go @@ -7,7 +7,7 @@ import ( "time" "cosmossdk.io/log" - "github.com/skip-mev/slinky/service/servers/oracle/types" + "github.com/skip-mev/connect/v2/service/servers/oracle/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/protocol/go.mod b/protocol/go.mod index b2224d6ad0..2af0fc5601 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -3,26 +3,26 @@ module github.com/dydxprotocol/v4-chain/protocol go 1.22.2 require ( - cosmossdk.io/api v0.7.5 + cosmossdk.io/api v0.7.6 cosmossdk.io/math v1.3.0 github.com/Shopify/sarama v1.37.2 - github.com/cometbft/cometbft v0.38.10 + github.com/cometbft/cometbft v0.38.12 github.com/cometbft/cometbft-db v0.12.0 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/cosmos-sdk v0.50.9 + github.com/cosmos/cosmos-sdk v0.50.10 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/gogoproto v1.6.0 + github.com/cosmos/gogoproto v1.7.0 github.com/go-playground/validator/v10 v10.14.0 - github.com/gofrs/flock v0.8.1 + github.com/gofrs/flock v0.12.1 github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.4 - github.com/golangci/golangci-lint v1.59.1 + github.com/golangci/golangci-lint v1.61.0 github.com/google/go-cmp v0.6.0 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/h2non/gock v1.2.0 - github.com/holiman/uint256 v1.3.0 + github.com/holiman/uint256 v1.3.1 github.com/ory/dockertest v3.3.5+incompatible github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 @@ -30,11 +30,11 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - github.com/vektra/mockery/v2 v2.44.1 + github.com/vektra/mockery/v2 v2.46.0 github.com/zyedidia/generic v1.0.0 - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/grpc v1.65.0 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.67.1 gopkg.in/DataDog/dd-trace-go.v1 v1.48.0 gopkg.in/typ.v4 v4.1.0 ) @@ -43,22 +43,22 @@ require ( cosmossdk.io/client/v2 v2.0.0-beta.4 cosmossdk.io/core v0.12.0 cosmossdk.io/errors v1.0.1 - cosmossdk.io/log v1.4.0 - cosmossdk.io/store v1.1.0 - cosmossdk.io/tools/confix v0.1.1 + cosmossdk.io/log v1.4.1 + cosmossdk.io/store v1.1.1 + cosmossdk.io/tools/confix v0.1.2 cosmossdk.io/x/circuit v0.1.1 - cosmossdk.io/x/evidence v0.1.0 - cosmossdk.io/x/feegrant v0.1.0 - cosmossdk.io/x/tx v0.13.4 + cosmossdk.io/x/evidence v0.1.1 + cosmossdk.io/x/feegrant v0.1.1 + cosmossdk.io/x/tx v0.13.5 cosmossdk.io/x/upgrade v0.1.4 github.com/burdiyan/kafkautil v0.0.0-20190131162249-eaf83ed22d5b github.com/cosmos/cosmos-db v1.0.2 - github.com/cosmos/iavl v1.1.2 - github.com/cosmos/ibc-go/modules/capability v1.0.0 - github.com/cosmos/ibc-go/v8 v8.3.2 + github.com/cosmos/iavl v1.2.0 + github.com/cosmos/ibc-go/modules/capability v1.0.1 + github.com/cosmos/ibc-go/v8 v8.5.0 github.com/cosmos/rosetta v0.50.3 github.com/deckarep/golang-set/v2 v2.6.0 - github.com/ethereum/go-ethereum v1.14.7 + github.com/ethereum/go-ethereum v1.14.10 github.com/go-kit/log v0.2.1 github.com/gorilla/websocket v1.5.3 github.com/hashicorp/go-metrics v0.5.3 @@ -66,10 +66,10 @@ require ( github.com/pelletier/go-toml v1.9.5 github.com/rs/zerolog v1.33.0 github.com/shopspring/decimal v1.3.1 - github.com/skip-mev/slinky v1.0.8 + github.com/skip-mev/connect/v2 v2.1.0 github.com/spf13/viper v1.19.0 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d - google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 google.golang.org/protobuf v1.34.2 gotest.tools/v3 v3.5.1 ) @@ -77,32 +77,34 @@ require ( require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/storage v1.38.0 // indirect + cloud.google.com/go v0.115.1 // indirect + cloud.google.com/go/auth v0.9.3 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/iam v1.2.0 // indirect + cloud.google.com/go/storage v1.43.0 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/depinject v1.0.0 // indirect - filippo.io/edwards25519 v1.0.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect github.com/4meepo/tagalign v1.3.4 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/Abirdcfly/dupword v0.0.14 // indirect + github.com/Abirdcfly/dupword v0.1.1 // indirect github.com/Antonboom/errname v0.1.13 // indirect github.com/Antonboom/nilnil v0.1.9 // indirect - github.com/Antonboom/testifylint v1.3.1 // indirect + github.com/Antonboom/testifylint v1.4.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/BurntSushi/toml v1.4.0 // indirect - github.com/Crocmagnon/fatcontext v0.2.2 // indirect + github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect + github.com/Crocmagnon/fatcontext v0.5.2 // indirect github.com/DataDog/datadog-go v4.8.2+incompatible // indirect github.com/DataDog/datadog-go/v5 v5.0.2 // indirect github.com/DataDog/gostackparse v0.5.0 // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect + github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect github.com/GeertJohan/go.rice v1.0.3 // indirect github.com/IBM/sarama v1.40.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect @@ -119,14 +121,14 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/bits-and-blooms/bitset v1.14.2 // indirect github.com/bkielbasa/cyclop v1.2.1 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v4 v4.2.1 // indirect + github.com/bombsimon/wsl/v4 v4.4.1 // indirect github.com/breml/bidichk v0.2.7 // indirect github.com/breml/errchkjson v0.3.6 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/butuzov/ireturn v0.3.0 // indirect github.com/butuzov/mirror v1.2.0 // indirect @@ -139,12 +141,12 @@ require ( github.com/chavacava/garif v0.1.0 // indirect github.com/chigopher/pathlib v0.19.1 // indirect github.com/chzyer/readline v1.5.1 // indirect - github.com/ckaznocha/intrange v0.1.2 // indirect + github.com/ckaznocha/intrange v0.2.0 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v1.1.1 // indirect + github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect @@ -153,16 +155,17 @@ require ( github.com/containerd/continuity v0.3.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/ics23/go v0.10.0 // indirect - github.com/cosmos/interchain-security/v5 v5.1.1 // indirect + github.com/cosmos/ics23/go v0.11.0 // indirect + github.com/cosmos/interchain-security/v6 v6.1.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/creachadair/atomicfile v0.3.1 // indirect github.com/creachadair/tomledit v0.0.24 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/daaku/go.zipexe v1.0.2 // indirect - github.com/daixiang0/gci v0.13.4 // indirect + github.com/daixiang0/gci v0.13.5 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect @@ -181,6 +184,7 @@ require ( github.com/eapache/queue v1.1.0 // indirect github.com/emicklei/dot v1.6.1 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.17.0 // indirect github.com/fatih/structtag v1.2.0 // indirect @@ -197,7 +201,7 @@ require ( github.com/go-critic/go-critic v0.11.4 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -210,16 +214,16 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.0.0 // indirect + github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect - github.com/golang/glog v1.2.1 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect + github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect github.com/golangci/misspell v0.6.0 // indirect github.com/golangci/modinfo v0.3.4 // indirect github.com/golangci/plugin-module-register v0.1.1 // indirect @@ -228,12 +232,12 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v2.0.8+incompatible // indirect github.com/google/orderedcode v0.0.1 // indirect - github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect - github.com/google/s2a-go v0.1.7 // indirect + github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.3 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/rpc v1.2.0 // indirect @@ -274,7 +278,7 @@ require ( github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect - github.com/jjti/go-spancheck v0.6.1 // indirect + github.com/jjti/go-spancheck v0.6.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -282,7 +286,7 @@ require ( github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect github.com/kisielk/errcheck v1.7.0 // indirect github.com/kkHAIKE/contextcheck v1.1.5 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kulti/thelper v0.6.3 // indirect @@ -308,7 +312,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/mgechev/revive v1.3.7 // indirect + github.com/mgechev/revive v1.3.9 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -317,7 +321,7 @@ require ( github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/moricho/tparallel v0.3.1 // indirect + github.com/moricho/tparallel v0.3.2 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect @@ -330,20 +334,20 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.4 // indirect - github.com/onsi/gomega v1.33.1 // indirect + github.com/onsi/gomega v1.34.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opencontainers/runc v1.1.12 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/polyfloyd/go-errorlint v1.5.2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/polyfloyd/go-errorlint v1.6.0 // indirect + github.com/prometheus/client_golang v1.20.4 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.52.2 // indirect - github.com/prometheus/procfs v0.13.0 // indirect - github.com/quasilyte/go-ruleguard v0.4.2 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect @@ -352,8 +356,8 @@ require ( github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.10.1 // indirect - github.com/ryancurrah/gomodguard v1.3.2 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/ryancurrah/gomodguard v1.3.5 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -361,13 +365,13 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.26.0 // indirect - github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 // indirect + github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect + github.com/securego/gosec/v2 v2.21.2 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sivchari/tenv v1.7.1 // indirect + github.com/sivchari/tenv v1.10.0 // indirect github.com/sonatard/noctx v0.0.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect @@ -378,22 +382,21 @@ require ( github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/supranational/blst v0.3.11 // indirect - github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect + github.com/supranational/blst v0.3.13 // indirect github.com/tdakkota/asciicheck v0.2.0 // indirect github.com/tendermint/go-amino v0.16.0 // indirect - github.com/tetafro/godot v1.4.16 // indirect + github.com/tetafro/godot v1.4.17 // indirect github.com/tidwall/btree v1.7.0 // indirect github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect github.com/timonwong/loggercheck v0.9.4 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - github.com/tomarrell/wrapcheck/v2 v2.8.3 // indirect + github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/ultraware/funlen v0.1.0 // indirect github.com/ultraware/whitespace v0.1.1 // indirect - github.com/uudashr/gocognit v1.1.2 // indirect + github.com/uudashr/gocognit v1.1.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect @@ -405,38 +408,38 @@ require ( github.com/zondax/ledger-go v0.14.3 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect go-simpler.org/musttag v0.12.2 // indirect - go-simpler.org/sloglint v0.7.1 // indirect + go-simpler.org/sloglint v0.7.2 // indirect go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect go.mongodb.org/mongo-driver v1.11.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.25.0 // indirect + golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.20.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.23.0 // indirect - google.golang.org/api v0.171.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect + golang.org/x/tools v0.25.0 // indirect + google.golang.org/api v0.196.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.4.7 // indirect - mvdan.cc/gofumpt v0.6.0 // indirect + honnef.co/go/tools v0.5.1 // indirect + mvdan.cc/gofumpt v0.7.0 // indirect mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect nhooyr.io/websocket v1.8.10 // indirect pgregory.net/rapid v1.1.0 // indirect @@ -446,7 +449,9 @@ require ( // Block for dep upgrades that would have been pulled in via Slinky replace ( + cosmossdk.io/x/evidence => cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/upgrade => cosmossdk.io/x/upgrade v0.1.1 + github.com/btcsuite/btcd/btcec/v2 => github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cosmos/ibc-go/v8 => github.com/cosmos/ibc-go/v8 v8.0.0 github.com/google/pprof => github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.18.0 diff --git a/protocol/go.sum b/protocol/go.sum index e3611326e6..c3fea57229 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -41,8 +41,8 @@ cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFO cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= +cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -104,6 +104,10 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= @@ -184,8 +188,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -319,8 +323,8 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= +cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -353,6 +357,8 @@ cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeN cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI= +cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= @@ -539,8 +545,8 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= -cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -606,8 +612,8 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= -cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.6 h1:PC20PcXy1xYKH2KU4RMurVoFjjKkCgYRbVAD4PdqUuY= +cosmossdk.io/api v0.7.6/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo= @@ -616,49 +622,49 @@ cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= 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.0 h1:Ttt9d6fQ0GlktwhcysOeNiIjixW7l0rYBocmoXOb11k= -cosmossdk.io/log v1.4.0/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= +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/tools/confix v0.1.1 h1:aexyRv9+y15veH3Qw16lxQwo+ki7r2I+g0yNTEFEQM8= -cosmossdk.io/tools/confix v0.1.1/go.mod h1:nQVvP1tHsGXS83PonPVWJtSbddIqyjEw99L4M3rPJyQ= +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= cosmossdk.io/x/circuit v0.1.1/go.mod h1:B6f/urRuQH8gjt4eLIXfZJucrbreuYrKh5CSjaOxr+Q= cosmossdk.io/x/evidence v0.1.0 h1:J6OEyDl1rbykksdGynzPKG5R/zm6TacwW2fbLTW4nCk= cosmossdk.io/x/evidence v0.1.0/go.mod h1:hTaiiXsoiJ3InMz1uptgF0BnGqROllAN8mwisOMMsfw= -cosmossdk.io/x/feegrant v0.1.0 h1:c7s3oAq/8/UO0EiN1H5BIjwVntujVTkYs35YPvvrdQk= -cosmossdk.io/x/feegrant v0.1.0/go.mod h1:4r+FsViJRpcZif/yhTn+E0E6OFfg4n0Lx+6cCtnZElU= -cosmossdk.io/x/tx v0.13.4 h1:Eg0PbJgeO0gM8p5wx6xa0fKR7hIV6+8lC56UrsvSo0Y= -cosmossdk.io/x/tx v0.13.4/go.mod h1:BkFqrnGGgW50Y6cwTy+JvgAhiffbGEKW6KF9ufcDpvk= +cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= +cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= +cosmossdk.io/x/tx v0.13.5 h1:FdnU+MdmFWn1pTsbfU0OCf2u6mJ8cqc1H4OMG418MLw= +cosmossdk.io/x/tx v0.13.5/go.mod h1:V6DImnwJMTq5qFjeGWpXNiT/fjgE4HtmclRmTqRVM3w= cosmossdk.io/x/upgrade v0.1.1 h1:aoPe2gNvH+Gwt/Pgq3dOxxQVU3j5P6Xf+DaUJTDZATc= cosmossdk.io/x/upgrade v0.1.1/go.mod h1:MNLptLPcIFK9CWt7Ra//8WUZAxweyRDNcbs5nkOcQy0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= -filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/Abirdcfly/dupword v0.0.14 h1:3U4ulkc8EUo+CaT105/GJ1BQwtgyj6+VaBVbAX11Ba8= -github.com/Abirdcfly/dupword v0.0.14/go.mod h1:VKDAbxdY8YbKUByLGg8EETzYSuC4crm9WwI6Y3S0cLI= +github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY= +github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM= github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= -github.com/Antonboom/testifylint v1.3.1 h1:Uam4q1Q+2b6H7gvk9RQFw6jyVDdpzIirFOOrbs14eG4= -github.com/Antonboom/testifylint v1.3.1/go.mod h1:NV0hTlteCkViPW9mSR4wEMfwp+Hs1T3dY60bkvSfhpM= +github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck= +github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Crocmagnon/fatcontext v0.2.2 h1:OrFlsDdOj9hW/oBEJBNSuH7QWf+E9WPVHw+x52bXVbk= -github.com/Crocmagnon/fatcontext v0.2.2/go.mod h1:WSn/c/+MMNiD8Pri0ahRj0o9jVpeowzavOQplBJw6u0= +github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA= +github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74= github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 h1:3nVO1nQyh64IUY6BPZUpMYMZ738Pu+LsMt3E0eqqIYw= github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583/go.mod h1:EP9f4GqaDJyP1F5jTNMtzdIpw3JpNs3rMSJOnYywCiw= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.42.0-rc.1 h1:Rmz52Xlc5k3WzAHzD0SCH4USCzyti7EbK4HtrHys3ME= @@ -678,16 +684,16 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.3 h1:k5viR+xGtIhF61125vCE1cmJ5957RQGXG6dmbaWZSmI= github.com/GeertJohan/go.rice v1.0.3/go.mod h1:XVdrU4pW00M4ikZed5q56tPf1v2KwnIKeIdc9CBYNt4= github.com/IBM/sarama v1.40.1 h1:lL01NNg/iBeigUbT+wpPysuTYW6roHo6kc1QrffRf0k= github.com/IBM/sarama v1.40.1/go.mod h1:+5OFwA5Du9I6QrznhaMHsuwWdWZNMjaBSIxEWEgKOYE= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -750,16 +756,16 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc= +github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v4 v4.2.1 h1:Cxg6u+XDWff75SIFFmNsqnIOgob+Q9hG6y/ioKbRFiM= -github.com/bombsimon/wsl/v4 v4.2.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= +github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= +github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= @@ -823,8 +829,8 @@ github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/ckaznocha/intrange v0.1.2 h1:3Y4JAxcMntgb/wABQ6e8Q8leMd26JbX2790lIss9MTI= -github.com/ckaznocha/intrange v0.1.2/go.mod h1:RWffCw/vKBwHeOEwWdCikAtY0q4gGt8VhJZEEA5n+RE= +github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs= +github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -849,8 +855,8 @@ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/e github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -879,16 +885,16 @@ github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4x github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= -github.com/cosmos/gogoproto v1.6.0 h1:Xm0F/96O5Ox4g6xGgjA41rWaaPjYtOdTi59uBcV2qEE= -github.com/cosmos/gogoproto v1.6.0/go.mod h1:Y+g956rcUf2vr4uwtCcK/1Xx9BWVluCtcI9vsh0GHmk= -github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= -github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= +github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= +github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= github.com/cosmos/ibc-go/v8 v8.0.0 h1:QKipnr/NGwc+9L7NZipURvmSIu+nw9jOIWTJuDBqOhg= github.com/cosmos/ibc-go/v8 v8.0.0/go.mod h1:C6IiJom0F3cIQCD5fKwVPDrDK9j/xTu563AWuOmXois= -github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= -github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= -github.com/cosmos/interchain-security/v5 v5.1.1 h1:xmRRMeE4xoc+JAZUh0XzXFYWaGBtzFFj5SETuOgnEnY= -github.com/cosmos/interchain-security/v5 v5.1.1/go.mod h1:vmeTcTxFCl1eV0o6xpl/IRT7Basz0szVVGzbppnInMg= +github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= +github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= +github.com/cosmos/interchain-security/v6 v6.1.0 h1:ycTpT+If90nSEvRVu86ThPJxNtcmnOMjJmFC9ptd/yo= +github.com/cosmos/interchain-security/v6 v6.1.0/go.mod h1:+5zIZEzkL4yNHB/UWXCu75t6GeEgEmWHbz5OnBWiL0o= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -914,8 +920,8 @@ github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDU github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daaku/go.zipexe v1.0.2 h1:Zg55YLYTr7M9wjKn8SY/WcpuuEi+kR2u4E8RhvpyXmk= github.com/daaku/go.zipexe v1.0.2/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= -github.com/daixiang0/gci v0.13.4 h1:61UGkmpoAcxHM2hhNkZEf5SzwQtWJXTSws7jaPyqwlw= -github.com/daixiang0/gci v0.13.4/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= +github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= +github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -986,10 +992,10 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+ github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= -github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= +github.com/ethereum/go-ethereum v1.14.10 h1:kC24WjYeRjDy86LVo6MfF5Xs7nnUu+XG4AjaYIaZYko= +github.com/ethereum/go-ethereum v1.14.10/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -1002,8 +1008,6 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= -github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= -github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -1061,8 +1065,8 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -1078,6 +1082,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -1106,8 +1112,8 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc= -github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -1120,8 +1126,8 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= @@ -1135,8 +1141,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1180,10 +1186,10 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXi github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g= -github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= -github.com/golangci/golangci-lint v1.59.1 h1:CRRLu1JbhK5avLABFJ/OHVSQ0Ie5c4ulsOId1h3TTks= -github.com/golangci/golangci-lint v1.59.1/go.mod h1:jX5Oif4C7P0j9++YB2MMJmoNrb01NJ8ITqKWNLewThg= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= +github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8= +github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8= github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= @@ -1227,8 +1233,9 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= @@ -1237,8 +1244,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -1251,8 +1258,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3 h1:QRje2j5GZimBzlbhGA2V2QlGNgL8G6e+wGo/+/2bWI0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -1267,8 +1274,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= @@ -1360,8 +1367,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= -github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -1406,8 +1413,8 @@ github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jjti/go-spancheck v0.6.1 h1:ZK/wE5Kyi1VX3PJpUO2oEgeoI4FWOUm7Shb2Gbv5obI= -github.com/jjti/go-spancheck v0.6.1/go.mod h1:vF1QkOO159prdo6mHRxak2CpzDpHAfKiPUDP/NeRnX8= +github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= +github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -1444,8 +1451,8 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= +github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1529,8 +1536,8 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE= -github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= +github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A= +github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= @@ -1554,8 +1561,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= -github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= +github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= +github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -1591,12 +1598,12 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU= -github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= +github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -1620,8 +1627,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1645,8 +1652,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.5.2 h1:SJhVik3Umsjh7mte1vE0fVZ5T1gznasQG3PV7U5xFdA= -github.com/polyfloyd/go-errorlint v1.5.2/go.mod h1:sH1QC1pxxi0fFecsVIzBmxtrgd9IF/SkJpA6wqyKAJs= +github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY= +github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= @@ -1661,10 +1668,10 @@ github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpj github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= -github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= -github.com/quasilyte/go-ruleguard v0.4.2 h1:htXcXDK6/rO12kiTHKfHuqR4kr3Y4M0J0rOL6CH/BYs= -github.com/quasilyte/go-ruleguard v0.4.2/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -1690,8 +1697,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -1700,8 +1707,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/ryancurrah/gomodguard v1.3.2 h1:CuG27ulzEB1Gu5Dk5gP8PFxSOZ3ptSdP5iI/3IXxM18= -github.com/ryancurrah/gomodguard v1.3.2/go.mod h1:LqdemiFomEjcxOqirbQCb3JFvSxH2JUYMerTFd3sF2o= +github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= +github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= @@ -1716,12 +1723,12 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.26.0 h1:LONR2hNVKxRmzIrZR0PhSF3mhCAzvnr+DcUiHgREfXE= -github.com/sashamelentyev/usestdlibvars v1.26.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= +github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs= -github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 h1:rnO6Zp1YMQwv8AyxzuwsVohljJgp4L0ZqiCgtACsPsc= -github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9/go.mod h1:dg7lPlu/xK/Ut9SedURCoZbVCR4yC7fM65DtH9/CDHs= +github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M= +github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= @@ -1736,12 +1743,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= -github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0= +github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY= github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610 h1:4JlsiRVt/YZOvrKH525T7sZXgEWUEjqSDMwE6fXNbdo= github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610/go.mod h1:kB8gFZX07CyJnw8q9iEZijI3qJTIe1K/Y++P5VGkrcg= -github.com/skip-mev/slinky v1.0.8 h1:F1dEnMI/fxTcTObVg0DxlzKa9QGqvgdjF9sIihtoBZA= -github.com/skip-mev/slinky v1.0.8/go.mod h1:CUW4fOkrsJ2Sbgv1t/VJUU68QY+zdkYwcs20QE9gpn8= +github.com/skip-mev/connect/v2 v2.1.0 h1:YYGtVBug3ZDy+uE+iGrlWtSd+shKt82vajEzddiciiw= +github.com/skip-mev/connect/v2 v2.1.0/go.mod h1:O/575IPwdz/VSJQip4ETrabACsBbesv5h2E7nsExU/Q= github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -1795,12 +1802,10 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= -github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= +github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= -github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -1811,8 +1816,8 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= -github.com/tetafro/godot v1.4.16 h1:4ChfhveiNLk4NveAZ9Pu2AN8QZ2nkUGFuadM9lrr5D0= -github.com/tetafro/godot v1.4.16/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs= +github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -1828,8 +1833,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tomarrell/wrapcheck/v2 v2.8.3 h1:5ov+Cbhlgi7s/a42BprYoxsr73CbdMUTzE3bRDFASUs= -github.com/tomarrell/wrapcheck/v2 v2.8.3/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= +github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -1847,12 +1852,12 @@ github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givT github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= -github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= +github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= +github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/vektra/mockery/v2 v2.44.1 h1:lfvocO3HklLp68gezPBVaHl+5rKXloGCO7eTEXh71dA= -github.com/vektra/mockery/v2 v2.44.1/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= +github.com/vektra/mockery/v2 v2.46.0 h1:DKIFj6hAPGwmOYiWfWzdsQtBgU8ozPXo3Bwbmf+Ku80= +github.com/vektra/mockery/v2 v2.46.0/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= @@ -1895,8 +1900,8 @@ go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs= go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM= -go-simpler.org/sloglint v0.7.1 h1:qlGLiqHbN5islOxjeLXoPtUdZXb669RW+BDQ+xOSNoU= -go-simpler.org/sloglint v0.7.1/go.mod h1:OlaVDRh/FKKd4X4sIMbsz8st97vomydceL146Fthh/c= +go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= +go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 h1:qxen9oVGzDdIRP6ejyAJc760RwW4SnVDiTYTzwnXuxo= go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5/go.mod h1:eW0HG9/oHQhvRCvb1/pIXW4cOvtDqeQK+XSi3TnwaXY= go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= @@ -1910,18 +1915,18 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1972,8 +1977,8 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1990,8 +1995,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= @@ -2040,8 +2045,8 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2111,8 +2116,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2146,8 +2151,8 @@ golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4 golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2255,7 +2260,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2276,8 +2280,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2291,8 +2295,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2311,16 +2315,16 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2394,15 +2398,14 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2410,9 +2413,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= @@ -2482,8 +2484,8 @@ google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjY google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= -google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= +google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2631,21 +2633,21 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f h1:b1Ln/PG8orm0SsBbHZWke8dDp2lrCD4jSmfglFpTZbk= -google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -2688,8 +2690,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2754,8 +2756,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs= -honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= +honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= +honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU= inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -2792,8 +2794,8 @@ modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo= -mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA= +mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= +mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/protocol/lib/marketmap/utils.go b/protocol/lib/marketmap/utils.go index 18d82861d7..9cad05780e 100644 --- a/protocol/lib/marketmap/utils.go +++ b/protocol/lib/marketmap/utils.go @@ -2,9 +2,9 @@ package marketmap import ( pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - dydx "github.com/skip-mev/slinky/providers/apis/dydx" - dydxtypes "github.com/skip-mev/slinky/providers/apis/dydx/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + dydx "github.com/skip-mev/connect/v2/providers/apis/dydx" + dydxtypes "github.com/skip-mev/connect/v2/providers/apis/dydx/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) // Construct a MarketMap struct from a slice of MarketParams diff --git a/protocol/lib/marketmap/utils_test.go b/protocol/lib/marketmap/utils_test.go index 94f6ce075d..eb8f6ce4f3 100644 --- a/protocol/lib/marketmap/utils_test.go +++ b/protocol/lib/marketmap/utils_test.go @@ -5,8 +5,8 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/lib/marketmap" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/lib/slinky/utils.go b/protocol/lib/slinky/utils.go index 1a3417a9cc..0fa0c71737 100644 --- a/protocol/lib/slinky/utils.go +++ b/protocol/lib/slinky/utils.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/skip-mev/slinky/pkg/types" + "github.com/skip-mev/connect/v2/pkg/types" ) /* diff --git a/protocol/lib/slinky/utils_test.go b/protocol/lib/slinky/utils_test.go index a2ee405e4b..6d9bc388fc 100644 --- a/protocol/lib/slinky/utils_test.go +++ b/protocol/lib/slinky/utils_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/skip-mev/slinky/pkg/types" + "github.com/skip-mev/connect/v2/pkg/types" "github.com/stretchr/testify/require" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" diff --git a/protocol/mocks/AnteDecorator.go b/protocol/mocks/AnteDecorator.go index bf8874661a..795e56da2e 100644 --- a/protocol/mocks/AnteDecorator.go +++ b/protocol/mocks/AnteDecorator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/AppOptions.go b/protocol/mocks/AppOptions.go index 824a897ff5..48c5d2d8ec 100644 --- a/protocol/mocks/AppOptions.go +++ b/protocol/mocks/AppOptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/BankKeeper.go b/protocol/mocks/BankKeeper.go index e2dc2f1cab..b3c401d63a 100644 --- a/protocol/mocks/BankKeeper.go +++ b/protocol/mocks/BankKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/BridgeKeeper.go b/protocol/mocks/BridgeKeeper.go index 972fccb630..c05e3a15c5 100644 --- a/protocol/mocks/BridgeKeeper.go +++ b/protocol/mocks/BridgeKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/BridgeQueryClient.go b/protocol/mocks/BridgeQueryClient.go index 849c7a282d..e33e086243 100644 --- a/protocol/mocks/BridgeQueryClient.go +++ b/protocol/mocks/BridgeQueryClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/BridgeServiceClient.go b/protocol/mocks/BridgeServiceClient.go index 598e51f7cb..afe264e811 100644 --- a/protocol/mocks/BridgeServiceClient.go +++ b/protocol/mocks/BridgeServiceClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/CacheMultiStore.go b/protocol/mocks/CacheMultiStore.go index b5e0d29d24..f3cd464625 100644 --- a/protocol/mocks/CacheMultiStore.go +++ b/protocol/mocks/CacheMultiStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ClobKeeper.go b/protocol/mocks/ClobKeeper.go index cd70f7d85d..2a7b5cfd9c 100644 --- a/protocol/mocks/ClobKeeper.go +++ b/protocol/mocks/ClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/Configurator.go b/protocol/mocks/Configurator.go index 4aa135d751..fc0ff2b1ae 100644 --- a/protocol/mocks/Configurator.go +++ b/protocol/mocks/Configurator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/DelayMsgKeeper.go b/protocol/mocks/DelayMsgKeeper.go index cc7ed98c79..04d6e65d68 100644 --- a/protocol/mocks/DelayMsgKeeper.go +++ b/protocol/mocks/DelayMsgKeeper.go @@ -1,3 +1,4 @@ + // Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/protocol/mocks/EthClient.go b/protocol/mocks/EthClient.go index 28e3194edf..b3c36bcf83 100644 --- a/protocol/mocks/EthClient.go +++ b/protocol/mocks/EthClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ExchangeConfigUpdater.go b/protocol/mocks/ExchangeConfigUpdater.go index 266d2c9592..d27f91630e 100644 --- a/protocol/mocks/ExchangeConfigUpdater.go +++ b/protocol/mocks/ExchangeConfigUpdater.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ExchangeQueryHandler.go b/protocol/mocks/ExchangeQueryHandler.go index 575335c728..fad03298d1 100644 --- a/protocol/mocks/ExchangeQueryHandler.go +++ b/protocol/mocks/ExchangeQueryHandler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ExchangeToMarketPrices.go b/protocol/mocks/ExchangeToMarketPrices.go index 34d89c65ce..27c866646f 100644 --- a/protocol/mocks/ExchangeToMarketPrices.go +++ b/protocol/mocks/ExchangeToMarketPrices.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ExtendVoteHandler.go b/protocol/mocks/ExtendVoteHandler.go index 755e96c66c..f8581316fb 100644 --- a/protocol/mocks/ExtendVoteHandler.go +++ b/protocol/mocks/ExtendVoteHandler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/FileHandler.go b/protocol/mocks/FileHandler.go index 04cfcd6b3d..0a9da0fece 100644 --- a/protocol/mocks/FileHandler.go +++ b/protocol/mocks/FileHandler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/GrpcClient.go b/protocol/mocks/GrpcClient.go index 77444c79f5..d489319131 100644 --- a/protocol/mocks/GrpcClient.go +++ b/protocol/mocks/GrpcClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/GrpcServer.go b/protocol/mocks/GrpcServer.go index 4ed12be5f4..a3e713fc74 100644 --- a/protocol/mocks/GrpcServer.go +++ b/protocol/mocks/GrpcServer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/HealthCheckable.go b/protocol/mocks/HealthCheckable.go index 57b818ab0c..88acd77670 100644 --- a/protocol/mocks/HealthCheckable.go +++ b/protocol/mocks/HealthCheckable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/IndexerEventManager.go b/protocol/mocks/IndexerEventManager.go index b9529b8c2c..adc8f24199 100644 --- a/protocol/mocks/IndexerEventManager.go +++ b/protocol/mocks/IndexerEventManager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/IndexerMessageSender.go b/protocol/mocks/IndexerMessageSender.go index e3eb79dba5..f211488e2e 100644 --- a/protocol/mocks/IndexerMessageSender.go +++ b/protocol/mocks/IndexerMessageSender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/Logger.go b/protocol/mocks/Logger.go index 77bb60a329..93fb545e95 100644 --- a/protocol/mocks/Logger.go +++ b/protocol/mocks/Logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/Makefile b/protocol/mocks/Makefile index a5741c4712..dc0fda979d 100644 --- a/protocol/mocks/Makefile +++ b/protocol/mocks/Makefile @@ -4,7 +4,7 @@ COSMOS_VERSION=$(shell go list -m all | grep "github.com/dydxprotocol/cosmos-sdk COSMOS_STORE_VERSION=$(shell go list -m all | grep "cosmossdk.io/store[^/]" | awk '{print $$NF}') COSMOS_LOG_VERSION=$(shell go list -m all | grep "cosmossdk.io/log[^/]" | awk '{print $$NF}') COSMOS_GOGOPROTO_VERSION=$(shell go list -m all | grep "github.com/cosmos/gogoproto[^/]" | awk '{print $$NF}') -SLINKY_VERSION=$(shell go list -m all | grep "github.com/skip-mev/slinky[^/]" | awk '{print $$NF}') +CONNECT_VERSION=$(shell go list -m all | grep "github.com/skip-mev/connect/v2[^/]" | awk '{print $$NF}') mock-clean: @rm -f ./mocks/*.go @@ -60,7 +60,7 @@ mock-gen: @go run github.com/vektra/mockery/v2 --name=PriceUpdateGenerator --dir=./app/prepare/prices --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=PriceFetcher --dir=./daemons/slinky/client --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=MarketPairFetcher --dir=./daemons/slinky/client --recursive --output=./mocks - @go run github.com/vektra/mockery/v2 --name=OracleClient --dir=$(GOPATH)/pkg/mod/github.com/skip-mev/slinky@$(SLINKY_VERSION)/service/clients/oracle --recursive --output=./mocks + @go run github.com/vektra/mockery/v2 --name=OracleClient --dir=$(GOPATH)/pkg/mod/github.com/skip-mev/connect/v2@$(CONNECT_VERSION)/service/clients/oracle --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=ExtendVoteHandler --dir=$(GOPATH)/pkg/mod/github.com/dydxprotocol/cosmos-sdk@$(COSMOS_VERSION)/types --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=UpdateMarketPriceTxDecoder --dir=./app/process --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=AssetsKeeper --dir=./x//types --recursive --output=./mocks diff --git a/protocol/mocks/MarketPairFetcher.go b/protocol/mocks/MarketPairFetcher.go index fa9588f982..9492dcc903 100644 --- a/protocol/mocks/MarketPairFetcher.go +++ b/protocol/mocks/MarketPairFetcher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks @@ -10,7 +10,7 @@ import ( mock "github.com/stretchr/testify/mock" - types "github.com/skip-mev/slinky/pkg/types" + types "github.com/skip-mev/connect/v2/pkg/types" ) // MarketPairFetcher is an autogenerated mock type for the MarketPairFetcher type diff --git a/protocol/mocks/MemClob.go b/protocol/mocks/MemClob.go index e5f0aa26bf..abccc20590 100644 --- a/protocol/mocks/MemClob.go +++ b/protocol/mocks/MemClob.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/MemClobKeeper.go b/protocol/mocks/MemClobKeeper.go index 032e175d12..0328c184d7 100644 --- a/protocol/mocks/MemClobKeeper.go +++ b/protocol/mocks/MemClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/MsgRouter.go b/protocol/mocks/MsgRouter.go index f197b38d9c..4c81bc9494 100644 --- a/protocol/mocks/MsgRouter.go +++ b/protocol/mocks/MsgRouter.go @@ -46,4 +46,4 @@ func NewMsgRouter(t interface { t.Cleanup(func() { mock.AssertExpectations(t) }) return mock -} +} \ No newline at end of file diff --git a/protocol/mocks/MultiStore.go b/protocol/mocks/MultiStore.go index 20e9c3830a..f64af9eb1b 100644 --- a/protocol/mocks/MultiStore.go +++ b/protocol/mocks/MultiStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/OracleClient.go b/protocol/mocks/OracleClient.go index 651361d160..883eed43ba 100644 --- a/protocol/mocks/OracleClient.go +++ b/protocol/mocks/OracleClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks @@ -9,7 +9,7 @@ import ( mock "github.com/stretchr/testify/mock" - types "github.com/skip-mev/slinky/service/servers/oracle/types" + types "github.com/skip-mev/connect/v2/service/servers/oracle/types" ) // OracleClient is an autogenerated mock type for the OracleClient type diff --git a/protocol/mocks/PerpetualsClobKeeper.go b/protocol/mocks/PerpetualsClobKeeper.go index fdd11d89e4..6af5dd104a 100644 --- a/protocol/mocks/PerpetualsClobKeeper.go +++ b/protocol/mocks/PerpetualsClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PerpetualsKeeper.go b/protocol/mocks/PerpetualsKeeper.go index fb83519c53..38721a5f1e 100644 --- a/protocol/mocks/PerpetualsKeeper.go +++ b/protocol/mocks/PerpetualsKeeper.go @@ -469,4 +469,4 @@ func NewPerpetualsKeeper(t interface { t.Cleanup(func() { mock.AssertExpectations(t) }) return mock -} +} \ No newline at end of file diff --git a/protocol/mocks/PrepareBridgeKeeper.go b/protocol/mocks/PrepareBridgeKeeper.go index 36fca8fedd..9337661647 100644 --- a/protocol/mocks/PrepareBridgeKeeper.go +++ b/protocol/mocks/PrepareBridgeKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PrepareClobKeeper.go b/protocol/mocks/PrepareClobKeeper.go index 8105410fb6..a52d3c3b68 100644 --- a/protocol/mocks/PrepareClobKeeper.go +++ b/protocol/mocks/PrepareClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PreparePerpetualsKeeper.go b/protocol/mocks/PreparePerpetualsKeeper.go index f049653c34..44323ead57 100644 --- a/protocol/mocks/PreparePerpetualsKeeper.go +++ b/protocol/mocks/PreparePerpetualsKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PriceFeedMutableMarketConfigs.go b/protocol/mocks/PriceFeedMutableMarketConfigs.go index 3190949974..66624fa1c3 100644 --- a/protocol/mocks/PriceFeedMutableMarketConfigs.go +++ b/protocol/mocks/PriceFeedMutableMarketConfigs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PriceFetcher.go b/protocol/mocks/PriceFetcher.go index b00ee2de3e..0b9c698479 100644 --- a/protocol/mocks/PriceFetcher.go +++ b/protocol/mocks/PriceFetcher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PriceUpdateGenerator.go b/protocol/mocks/PriceUpdateGenerator.go index a33d85d6bd..c8f4dd073d 100644 --- a/protocol/mocks/PriceUpdateGenerator.go +++ b/protocol/mocks/PriceUpdateGenerator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/PricesKeeper.go b/protocol/mocks/PricesKeeper.go index 7eecd7edb1..4776407623 100644 --- a/protocol/mocks/PricesKeeper.go +++ b/protocol/mocks/PricesKeeper.go @@ -1,13 +1,17 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks import ( + context "context" + log "cosmossdk.io/log" - oracletypes "github.com/skip-mev/slinky/x/oracle/types" + mock "github.com/stretchr/testify/mock" - pkgtypes "github.com/skip-mev/slinky/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/x/oracle/types" + + pkgtypes "github.com/skip-mev/connect/v2/pkg/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" @@ -25,7 +29,7 @@ func (_m *PricesKeeper) AddCurrencyPairIDToStore(ctx types.Context, id uint32, c } // CreateMarket provides a mock function with given fields: ctx, param, price -func (_m *PricesKeeper) CreateMarket(ctx types.Context, param pricestypes.MarketParam, price pricestypes.MarketPrice) (pricestypes.MarketParam, error) { +func (_m *PricesKeeper) CreateMarket(ctx context.Context, param pricestypes.MarketParam, price pricestypes.MarketPrice) (pricestypes.MarketParam, error) { ret := _m.Called(ctx, param, price) if len(ret) == 0 { @@ -34,16 +38,16 @@ func (_m *PricesKeeper) CreateMarket(ctx types.Context, param pricestypes.Market var r0 pricestypes.MarketParam var r1 error - if rf, ok := ret.Get(0).(func(types.Context, pricestypes.MarketParam, pricestypes.MarketPrice) (pricestypes.MarketParam, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, pricestypes.MarketParam, pricestypes.MarketPrice) (pricestypes.MarketParam, error)); ok { return rf(ctx, param, price) } - if rf, ok := ret.Get(0).(func(types.Context, pricestypes.MarketParam, pricestypes.MarketPrice) pricestypes.MarketParam); ok { + if rf, ok := ret.Get(0).(func(context.Context, pricestypes.MarketParam, pricestypes.MarketPrice) pricestypes.MarketParam); ok { r0 = rf(ctx, param, price) } else { r0 = ret.Get(0).(pricestypes.MarketParam) } - if rf, ok := ret.Get(1).(func(types.Context, pricestypes.MarketParam, pricestypes.MarketPrice) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, pricestypes.MarketParam, pricestypes.MarketPrice) error); ok { r1 = rf(ctx, param, price) } else { r1 = ret.Error(1) @@ -123,7 +127,7 @@ func (_m *PricesKeeper) GetAllMarketPrices(ctx types.Context) []pricestypes.Mark } // GetCurrencyPairFromID provides a mock function with given fields: ctx, id -func (_m *PricesKeeper) GetCurrencyPairFromID(ctx types.Context, id uint64) (pkgtypes.CurrencyPair, bool) { +func (_m *PricesKeeper) GetCurrencyPairFromID(ctx context.Context, id uint64) (pkgtypes.CurrencyPair, bool) { ret := _m.Called(ctx, id) if len(ret) == 0 { @@ -132,16 +136,16 @@ func (_m *PricesKeeper) GetCurrencyPairFromID(ctx types.Context, id uint64) (pkg var r0 pkgtypes.CurrencyPair var r1 bool - if rf, ok := ret.Get(0).(func(types.Context, uint64) (pkgtypes.CurrencyPair, bool)); ok { + if rf, ok := ret.Get(0).(func(context.Context, uint64) (pkgtypes.CurrencyPair, bool)); ok { return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(types.Context, uint64) pkgtypes.CurrencyPair); ok { + if rf, ok := ret.Get(0).(func(context.Context, uint64) pkgtypes.CurrencyPair); ok { r0 = rf(ctx, id) } else { r0 = ret.Get(0).(pkgtypes.CurrencyPair) } - if rf, ok := ret.Get(1).(func(types.Context, uint64) bool); ok { + if rf, ok := ret.Get(1).(func(context.Context, uint64) bool); ok { r1 = rf(ctx, id) } else { r1 = ret.Get(1).(bool) @@ -179,7 +183,7 @@ func (_m *PricesKeeper) GetExponent(ctx types.Context, ticker string) (int32, er } // GetIDForCurrencyPair provides a mock function with given fields: ctx, cp -func (_m *PricesKeeper) GetIDForCurrencyPair(ctx types.Context, cp pkgtypes.CurrencyPair) (uint64, bool) { +func (_m *PricesKeeper) GetIDForCurrencyPair(ctx context.Context, cp pkgtypes.CurrencyPair) (uint64, bool) { ret := _m.Called(ctx, cp) if len(ret) == 0 { @@ -188,16 +192,16 @@ func (_m *PricesKeeper) GetIDForCurrencyPair(ctx types.Context, cp pkgtypes.Curr var r0 uint64 var r1 bool - if rf, ok := ret.Get(0).(func(types.Context, pkgtypes.CurrencyPair) (uint64, bool)); ok { + if rf, ok := ret.Get(0).(func(context.Context, pkgtypes.CurrencyPair) (uint64, bool)); ok { return rf(ctx, cp) } - if rf, ok := ret.Get(0).(func(types.Context, pkgtypes.CurrencyPair) uint64); ok { + if rf, ok := ret.Get(0).(func(context.Context, pkgtypes.CurrencyPair) uint64); ok { r0 = rf(ctx, cp) } else { r0 = ret.Get(0).(uint64) } - if rf, ok := ret.Get(1).(func(types.Context, pkgtypes.CurrencyPair) bool); ok { + if rf, ok := ret.Get(1).(func(context.Context, pkgtypes.CurrencyPair) bool); ok { r1 = rf(ctx, cp) } else { r1 = ret.Get(1).(bool) @@ -283,7 +287,7 @@ func (_m *PricesKeeper) GetMarketPrice(ctx types.Context, id uint32) (pricestype } // GetPriceForCurrencyPair provides a mock function with given fields: ctx, cp -func (_m *PricesKeeper) GetPriceForCurrencyPair(ctx types.Context, cp pkgtypes.CurrencyPair) (oracletypes.QuotePrice, error) { +func (_m *PricesKeeper) GetPriceForCurrencyPair(ctx context.Context, cp pkgtypes.CurrencyPair) (oracletypes.QuotePrice, error) { ret := _m.Called(ctx, cp) if len(ret) == 0 { @@ -292,16 +296,16 @@ func (_m *PricesKeeper) GetPriceForCurrencyPair(ctx types.Context, cp pkgtypes.C var r0 oracletypes.QuotePrice var r1 error - if rf, ok := ret.Get(0).(func(types.Context, pkgtypes.CurrencyPair) (oracletypes.QuotePrice, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, pkgtypes.CurrencyPair) (oracletypes.QuotePrice, error)); ok { return rf(ctx, cp) } - if rf, ok := ret.Get(0).(func(types.Context, pkgtypes.CurrencyPair) oracletypes.QuotePrice); ok { + if rf, ok := ret.Get(0).(func(context.Context, pkgtypes.CurrencyPair) oracletypes.QuotePrice); ok { r0 = rf(ctx, cp) } else { r0 = ret.Get(0).(oracletypes.QuotePrice) } - if rf, ok := ret.Get(1).(func(types.Context, pkgtypes.CurrencyPair) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, pkgtypes.CurrencyPair) error); ok { r1 = rf(ctx, cp) } else { r1 = ret.Error(1) diff --git a/protocol/mocks/ProcessBridgeKeeper.go b/protocol/mocks/ProcessBridgeKeeper.go index b0a1493c7b..677b5ea3a8 100644 --- a/protocol/mocks/ProcessBridgeKeeper.go +++ b/protocol/mocks/ProcessBridgeKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ProcessClobKeeper.go b/protocol/mocks/ProcessClobKeeper.go index 92e5c3b08b..e552b27231 100644 --- a/protocol/mocks/ProcessClobKeeper.go +++ b/protocol/mocks/ProcessClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ProcessPerpetualKeeper.go b/protocol/mocks/ProcessPerpetualKeeper.go index 97615ae57d..3d9f89a727 100644 --- a/protocol/mocks/ProcessPerpetualKeeper.go +++ b/protocol/mocks/ProcessPerpetualKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/ProcessStakingKeeper.go b/protocol/mocks/ProcessStakingKeeper.go index 29f6f5acaf..30d1afedbe 100644 --- a/protocol/mocks/ProcessStakingKeeper.go +++ b/protocol/mocks/ProcessStakingKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/QueryClient.go b/protocol/mocks/QueryClient.go index 2e2eeefe3e..e8c611ebb3 100644 --- a/protocol/mocks/QueryClient.go +++ b/protocol/mocks/QueryClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/QueryServer.go b/protocol/mocks/QueryServer.go index 2db0d13114..4a7770a920 100644 --- a/protocol/mocks/QueryServer.go +++ b/protocol/mocks/QueryServer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/RequestHandler.go b/protocol/mocks/RequestHandler.go index ba03ea51a0..caa2a8369f 100644 --- a/protocol/mocks/RequestHandler.go +++ b/protocol/mocks/RequestHandler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/SendingKeeper.go b/protocol/mocks/SendingKeeper.go index 4d1ca91487..53a1d36e00 100644 --- a/protocol/mocks/SendingKeeper.go +++ b/protocol/mocks/SendingKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/Server.go b/protocol/mocks/Server.go index eb888a4b0a..2d7586246b 100644 --- a/protocol/mocks/Server.go +++ b/protocol/mocks/Server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/SubaccountsKeeper.go b/protocol/mocks/SubaccountsKeeper.go index 6c14481c68..13460f3180 100644 --- a/protocol/mocks/SubaccountsKeeper.go +++ b/protocol/mocks/SubaccountsKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/TimeProvider.go b/protocol/mocks/TimeProvider.go index 9b9bd347b8..a96f44ba8f 100644 --- a/protocol/mocks/TimeProvider.go +++ b/protocol/mocks/TimeProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/TxBuilder.go b/protocol/mocks/TxBuilder.go index 19e1f53f83..a67246abc7 100644 --- a/protocol/mocks/TxBuilder.go +++ b/protocol/mocks/TxBuilder.go @@ -148,4 +148,4 @@ func NewTxBuilder(t interface { t.Cleanup(func() { mock.AssertExpectations(t) }) return mock -} +} \ No newline at end of file diff --git a/protocol/mocks/TxConfig.go b/protocol/mocks/TxConfig.go index d4fee668f6..d38ca99199 100644 --- a/protocol/mocks/TxConfig.go +++ b/protocol/mocks/TxConfig.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/UpdateMarketPriceTxDecoder.go b/protocol/mocks/UpdateMarketPriceTxDecoder.go index 7194cefc72..b766a9c1c0 100644 --- a/protocol/mocks/UpdateMarketPriceTxDecoder.go +++ b/protocol/mocks/UpdateMarketPriceTxDecoder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/mocks/VaultKeeper.go b/protocol/mocks/VaultKeeper.go index ea86fcb55e..4ac58651de 100644 --- a/protocol/mocks/VaultKeeper.go +++ b/protocol/mocks/VaultKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.44.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks diff --git a/protocol/testing/e2e/gov/add_new_market_test.go b/protocol/testing/e2e/gov/add_new_market_test.go index f12c533c49..345a1d9752 100644 --- a/protocol/testing/e2e/gov/add_new_market_test.go +++ b/protocol/testing/e2e/gov/add_new_market_test.go @@ -6,7 +6,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/protocol/testing/e2e/gov/perpetuals_test.go b/protocol/testing/e2e/gov/perpetuals_test.go index e4a5feac4a..5ba02bd3a1 100644 --- a/protocol/testing/e2e/gov/perpetuals_test.go +++ b/protocol/testing/e2e/gov/perpetuals_test.go @@ -15,8 +15,8 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/testing/e2e/gov/prices_test.go b/protocol/testing/e2e/gov/prices_test.go index e6b77c5ec9..e1e220e358 100644 --- a/protocol/testing/e2e/gov/prices_test.go +++ b/protocol/testing/e2e/gov/prices_test.go @@ -14,7 +14,7 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/testutil/app/app.go b/protocol/testutil/app/app.go index 44f34b4b70..40de56f9e2 100644 --- a/protocol/testutil/app/app.go +++ b/protocol/testutil/app/app.go @@ -67,7 +67,7 @@ import ( satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" vesttypes "github.com/dydxprotocol/v4-chain/protocol/x/vest/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" "golang.org/x/exp/slices" ) diff --git a/protocol/testutil/constants/marketmap.go b/protocol/testutil/constants/marketmap.go index 32fbcb0796..c12de9f4c1 100644 --- a/protocol/testutil/constants/marketmap.go +++ b/protocol/testutil/constants/marketmap.go @@ -4,8 +4,8 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - marketmapmoduletypes "github.com/skip-mev/slinky/x/marketmap/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + marketmapmoduletypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) var GovAuthority = authtypes.NewModuleAddress(govtypes.ModuleName).String() diff --git a/protocol/testutil/keeper/clob.go b/protocol/testutil/keeper/clob.go index 0e1b1ba1e9..a7bdd239fa 100644 --- a/protocol/testutil/keeper/clob.go +++ b/protocol/testutil/keeper/clob.go @@ -34,7 +34,7 @@ import ( subkeeper "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/keeper" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/require" ) diff --git a/protocol/testutil/keeper/listing.go b/protocol/testutil/keeper/listing.go index 49f181ecbb..98f8e7f69f 100644 --- a/protocol/testutil/keeper/listing.go +++ b/protocol/testutil/keeper/listing.go @@ -15,7 +15,7 @@ import ( perpetualskeeper "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/keeper" priceskeeper "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/mock" "testing" diff --git a/protocol/testutil/keeper/marketmap.go b/protocol/testutil/keeper/marketmap.go index 266b88af54..8310b75463 100644 --- a/protocol/testutil/keeper/marketmap.go +++ b/protocol/testutil/keeper/marketmap.go @@ -5,10 +5,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/slinky/x/marketmap/types" + "github.com/skip-mev/connect/v2/x/marketmap/types" storetypes "cosmossdk.io/store/types" - keeper "github.com/skip-mev/slinky/x/marketmap/keeper" + keeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" ) func createMarketMapKeeper( diff --git a/protocol/testutil/keeper/perpetuals.go b/protocol/testutil/keeper/perpetuals.go index 0805ea94fc..b79300d625 100644 --- a/protocol/testutil/keeper/perpetuals.go +++ b/protocol/testutil/keeper/perpetuals.go @@ -25,7 +25,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" priceskeeper "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/require" ) diff --git a/protocol/testutil/keeper/prices.go b/protocol/testutil/keeper/prices.go index ef6c53a5fb..0022631dd1 100644 --- a/protocol/testutil/keeper/prices.go +++ b/protocol/testutil/keeper/prices.go @@ -25,7 +25,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" revsharekeeper "github.com/dydxprotocol/v4-chain/protocol/x/revshare/keeper" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) diff --git a/protocol/testutil/network/network.go b/protocol/testutil/network/network.go index d620a870cd..e4d156b6c1 100644 --- a/protocol/testutil/network/network.go +++ b/protocol/testutil/network/network.go @@ -29,7 +29,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/ci" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" "github.com/gofrs/flock" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/testutil/prices/cli/util.go b/protocol/testutil/prices/cli/util.go index 0dfa56e8d7..58291b75a8 100644 --- a/protocol/testutil/prices/cli/util.go +++ b/protocol/testutil/prices/cli/util.go @@ -8,7 +8,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/testutil/network" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/x/clob/keeper/process_operations.go b/protocol/x/clob/keeper/process_operations.go index 86808afb5d..057256554e 100644 --- a/protocol/x/clob/keeper/process_operations.go +++ b/protocol/x/clob/keeper/process_operations.go @@ -752,7 +752,7 @@ func (k Keeper) PersistMatchDeleveragingToState( // negative TNC subaccount was seen. if len(matchDeleveraging.GetFills()) == 0 { if !shouldDeleverageAtBankruptcyPrice { - return errorsmod.Wrapf( + return errorsmod.Wrap( types.ErrZeroFillDeleveragingForNonNegativeTncSubaccount, fmt.Sprintf( "PersistMatchDeleveragingToState: zero-fill deleveraging operation included for subaccount %+v"+ diff --git a/protocol/x/clob/module_test.go b/protocol/x/clob/module_test.go index ce1793e1cb..9c1903713c 100644 --- a/protocol/x/clob/module_test.go +++ b/protocol/x/clob/module_test.go @@ -33,7 +33,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/prices" prices_keeper "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" "github.com/grpc-ecosystem/grpc-gateway/runtime" - marketmap_keeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmap_keeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) diff --git a/protocol/x/delaymsg/keeper/delayed_message.go b/protocol/x/delaymsg/keeper/delayed_message.go index a89f2ea788..dd3395e62e 100644 --- a/protocol/x/delaymsg/keeper/delayed_message.go +++ b/protocol/x/delaymsg/keeper/delayed_message.go @@ -188,7 +188,7 @@ func validateSigners(signers [][]byte) error { ) } if !bytes.Equal(signers[0], types.ModuleAddress) { - return errorsmod.Wrapf( + return errorsmod.Wrap( types.ErrInvalidSigner, "message signer must be delaymsg module address", ) @@ -201,7 +201,7 @@ func (k Keeper) ValidateMsg(msg sdk.Msg, signers [][]byte) error { handler := k.router.Handler(msg) // If the message type is not routable, return an error. if handler == nil { - return errorsmod.Wrapf( + return errorsmod.Wrap( types.ErrMsgIsUnroutable, sdk.MsgTypeURL(msg), ) diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 82d190620d..54cab6e467 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -1,16 +1,14 @@ package keeper import ( + "context" "math" "math/big" - vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" - - satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" - "github.com/dydxprotocol/v4-chain/protocol/lib" - "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" sdk "github.com/cosmos/cosmos-sdk/types" gogotypes "github.com/cosmos/gogoproto/types" @@ -18,7 +16,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - "github.com/skip-mev/slinky/x/marketmap/types/tickermetadata" + "github.com/skip-mev/connect/v2/x/marketmap/types/tickermetadata" ) // Function to set hard cap on listed markets in module store @@ -41,10 +39,12 @@ func (k Keeper) GetMarketsHardCap(ctx sdk.Context) (hardCap uint32) { // Function to wrap the creation of a new market // Note: This will only list long-tail/isolated markets func (k Keeper) CreateMarket( - ctx sdk.Context, + ctx context.Context, ticker string, ) (marketId uint32, err error) { - marketId = k.PricesKeeper.AcquireNextMarketID(ctx) + sdkCtx := sdk.UnwrapSDKContext(ctx) + + marketId = k.PricesKeeper.AcquireNextMarketID(sdkCtx) // Get market details from marketmap // TODO: change to use util from marketmap when available @@ -52,14 +52,14 @@ func (k Keeper) CreateMarket( if err != nil { return 0, err } - marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, marketMapPair.String()) + marketMapDetails, err := k.MarketMapKeeper.GetMarket(sdkCtx, marketMapPair.String()) if err != nil { return 0, types.ErrMarketNotFound } // Create a new market market, err := k.PricesKeeper.CreateMarket( - ctx, + sdkCtx, pricestypes.MarketParam{ Id: marketId, Pair: ticker, diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index 052172c0f0..b806e91a79 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -22,9 +22,9 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" - "github.com/skip-mev/slinky/x/marketmap/types/tickermetadata" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" + "github.com/skip-mev/connect/v2/x/marketmap/types/tickermetadata" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" diff --git a/protocol/x/listing/keeper/msg_create_market_permissionless_test.go b/protocol/x/listing/keeper/msg_create_market_permissionless_test.go index a1f351e0b2..63b47043b4 100644 --- a/protocol/x/listing/keeper/msg_create_market_permissionless_test.go +++ b/protocol/x/listing/keeper/msg_create_market_permissionless_test.go @@ -12,9 +12,9 @@ import ( pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" - oracletypes "github.com/skip-mev/slinky/pkg/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" - "github.com/skip-mev/slinky/x/marketmap/types/tickermetadata" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" + "github.com/skip-mev/connect/v2/x/marketmap/types/tickermetadata" "github.com/stretchr/testify/require" "testing" diff --git a/protocol/x/listing/types/expected_keepers.go b/protocol/x/listing/types/expected_keepers.go index d6b72ac3f9..7676db370e 100644 --- a/protocol/x/listing/types/expected_keepers.go +++ b/protocol/x/listing/types/expected_keepers.go @@ -1,6 +1,7 @@ package types import ( + "context" "math/big" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" @@ -10,12 +11,12 @@ import ( perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) type PricesKeeper interface { CreateMarket( - ctx sdk.Context, + ctx context.Context, marketParam pricestypes.MarketParam, marketPrice pricestypes.MarketPrice, ) (pricestypes.MarketParam, error) @@ -40,12 +41,12 @@ type ClobKeeper interface { type MarketMapKeeper interface { GetMarket( - ctx sdk.Context, + ctx context.Context, ticker string, ) (marketmaptypes.Market, error) // Only used for testing purposes CreateMarket( - ctx sdk.Context, + ctx context.Context, market marketmaptypes.Market, ) error } diff --git a/protocol/x/prices/keeper/market.go b/protocol/x/prices/keeper/market.go index d5c76cc310..9523ad8846 100644 --- a/protocol/x/prices/keeper/market.go +++ b/protocol/x/prices/keeper/market.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "fmt" gogotypes "github.com/cosmos/gogoproto/types" @@ -20,11 +21,13 @@ import ( // This is the only path to creating new MarketPrices, so if we have a param // defined for a market, we should expect to see a price defined, and vice versa. func (k Keeper) CreateMarket( - ctx sdk.Context, + ctx context.Context, marketParam types.MarketParam, marketPrice types.MarketPrice, ) (types.MarketParam, error) { - if _, exists := k.GetMarketParam(ctx, marketParam.Id); exists { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if _, exists := k.GetMarketParam(sdkCtx, marketParam.Id); exists { return types.MarketParam{}, errorsmod.Wrapf( types.ErrMarketParamAlreadyExists, "market param with id %d already exists", @@ -40,9 +43,9 @@ func (k Keeper) CreateMarket( return types.MarketParam{}, err } // Stateful Validation - for _, market := range k.GetAllMarketParams(ctx) { + for _, market := range k.GetAllMarketParams(sdkCtx) { if market.Pair == marketParam.Pair { - return types.MarketParam{}, errorsmod.Wrapf( + return types.MarketParam{}, errorsmod.Wrap( types.ErrMarketParamPairAlreadyExists, marketParam.Pair, ) @@ -51,7 +54,7 @@ func (k Keeper) CreateMarket( // check that the market exists in market map currencyPair, err := slinky.MarketPairToCurrencyPair(marketParam.Pair) if err != nil { - return types.MarketParam{}, errorsmod.Wrapf( + return types.MarketParam{}, errorsmod.Wrap( types.ErrMarketPairConversionFailed, marketParam.Pair, ) @@ -59,7 +62,7 @@ func (k Keeper) CreateMarket( currencyPairStr := currencyPair.String() marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, currencyPairStr) if err != nil { - return types.MarketParam{}, errorsmod.Wrapf( + return types.MarketParam{}, errorsmod.Wrap( types.ErrTickerNotFoundInMarketMap, currencyPairStr, ) @@ -67,7 +70,7 @@ func (k Keeper) CreateMarket( // Check that the exponent of market price is the negation of the decimals value in the market map if marketPrice.Exponent != int32(marketMapDetails.Ticker.Decimals)*-1 { - return types.MarketParam{}, errorsmod.Wrapf( + return types.MarketParam{}, errorsmod.Wrap( types.ErrInvalidMarketPriceExponent, currencyPairStr, ) @@ -76,18 +79,18 @@ func (k Keeper) CreateMarket( paramBytes := k.cdc.MustMarshal(&marketParam) priceBytes := k.cdc.MustMarshal(&marketPrice) - marketParamStore := k.getMarketParamStore(ctx) + marketParamStore := k.getMarketParamStore(sdkCtx) marketParamStore.Set(lib.Uint32ToKey(marketParam.Id), paramBytes) - marketPriceStore := k.getMarketPriceStore(ctx) + marketPriceStore := k.getMarketPriceStore(sdkCtx) marketPriceStore.Set(lib.Uint32ToKey(marketPrice.Id), priceBytes) // add the pair to the currency-pair-id cache - k.AddCurrencyPairIDToStore(ctx, marketParam.Id, currencyPair) + k.AddCurrencyPairIDToStore(sdkCtx, marketParam.Id, currencyPair) // Generate indexer event. k.GetIndexerEventManager().AddTxnEvent( - ctx, + sdkCtx, indexerevents.SubtypeMarket, indexerevents.MarketEventVersion, indexer_manager.GetBytes( @@ -104,12 +107,12 @@ func (k Keeper) CreateMarket( metrics.SetMarketPairForTelemetry(marketParam.Id, marketParam.Pair) // create a new market rev share - k.RevShareKeeper.CreateNewMarketRevShare(ctx, marketParam.Id) + k.RevShareKeeper.CreateNewMarketRevShare(sdkCtx, marketParam.Id) // enable the market in the market map err = k.MarketMapKeeper.EnableMarket(ctx, currencyPairStr) if err != nil { - k.Logger(ctx).Error( + k.Logger(sdkCtx).Error( "failed to enable market in market map", "market ticker", currencyPairStr, @@ -130,7 +133,7 @@ func (k Keeper) GetExponent(ctx sdk.Context, ticker string) (int32, error) { marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, currencyPair.String()) if err != nil { - return 0, errorsmod.Wrapf( + return 0, errorsmod.Wrap( types.ErrTickerNotFoundInMarketMap, ticker, ) diff --git a/protocol/x/prices/keeper/market_param.go b/protocol/x/prices/keeper/market_param.go index e62f92fc88..e364e3fcec 100644 --- a/protocol/x/prices/keeper/market_param.go +++ b/protocol/x/prices/keeper/market_param.go @@ -42,17 +42,17 @@ func (k Keeper) ModifyMarketParam( // Validate update is permitted. for _, market := range k.GetAllMarketParams(ctx) { if market.Pair == updatedMarketParam.Pair && market.Id != updatedMarketParam.Id { - return types.MarketParam{}, errorsmod.Wrapf(types.ErrMarketParamPairAlreadyExists, updatedMarketParam.Pair) + return types.MarketParam{}, errorsmod.Wrap(types.ErrMarketParamPairAlreadyExists, updatedMarketParam.Pair) } } // Validate that modified market param has a corresponding ticker in MarketMap cp, err := slinky.MarketPairToCurrencyPair(updatedMarketParam.Pair) if err != nil { - return types.MarketParam{}, errorsmod.Wrapf(types.ErrMarketPairConversionFailed, updatedMarketParam.Pair) + return types.MarketParam{}, errorsmod.Wrap(types.ErrMarketPairConversionFailed, updatedMarketParam.Pair) } if _, err := k.MarketMapKeeper.GetMarket(ctx, cp.String()); err != nil { - return types.MarketParam{}, errorsmod.Wrapf(types.ErrTickerNotFoundInMarketMap, cp.String()) + return types.MarketParam{}, errorsmod.Wrap(types.ErrTickerNotFoundInMarketMap, cp.String()) } // Store the modified market param. diff --git a/protocol/x/prices/keeper/market_param_test.go b/protocol/x/prices/keeper/market_param_test.go index 1260bd005d..95644f3b3e 100644 --- a/protocol/x/prices/keeper/market_param_test.go +++ b/protocol/x/prices/keeper/market_param_test.go @@ -6,7 +6,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/metrics" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" errorsmod "cosmossdk.io/errors" @@ -247,7 +247,7 @@ func TestModifyMarketParam_Errors(t *testing.T) { minExchanges: uint32(1), minPriceChangePpm: uint32(50), exchangeConfigJson: validExchangeConfigJson, - expectedErr: errorsmod.Wrapf( + expectedErr: errorsmod.Wrap( types.ErrMarketParamPairAlreadyExists, "1-1", ).Error(), @@ -258,7 +258,7 @@ func TestModifyMarketParam_Errors(t *testing.T) { minExchanges: uint32(1), minPriceChangePpm: uint32(50), exchangeConfigJson: validExchangeConfigJson, - expectedErr: errorsmod.Wrapf( + expectedErr: errorsmod.Wrap( types.ErrTickerNotFoundInMarketMap, invalidUpdateCurrencyPair.String(), ).Error(), diff --git a/protocol/x/prices/keeper/market_test.go b/protocol/x/prices/keeper/market_test.go index dfdbb81341..f0323f2a57 100644 --- a/protocol/x/prices/keeper/market_test.go +++ b/protocol/x/prices/keeper/market_test.go @@ -10,8 +10,9 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go b/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go index ae3b4e95dd..f74702beae 100644 --- a/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go +++ b/protocol/x/prices/keeper/msg_server_create_oracle_market_test.go @@ -12,8 +12,8 @@ import ( pricestest "github.com/dydxprotocol/v4-chain/protocol/testutil/prices" "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/stretchr/testify/require" ) diff --git a/protocol/x/prices/keeper/slinky_adapter.go b/protocol/x/prices/keeper/slinky_adapter.go index 9cb12ae3e7..17aec50ae2 100644 --- a/protocol/x/prices/keeper/slinky_adapter.go +++ b/protocol/x/prices/keeper/slinky_adapter.go @@ -1,14 +1,15 @@ package keeper import ( + "context" "fmt" "cosmossdk.io/math" "cosmossdk.io/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" gogotypes "github.com/cosmos/gogoproto/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - oracletypes "github.com/skip-mev/slinky/x/oracle/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/x/oracle/types" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" @@ -27,24 +28,28 @@ func (k Keeper) getCurrencyPairIDStore(ctx sdk.Context) prefix.Store { return prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.CurrencyPairIDPrefix)) } -func (k Keeper) GetCurrencyPairFromID(ctx sdk.Context, id uint64) (cp slinkytypes.CurrencyPair, found bool) { - mp, found := k.GetMarketParam(ctx, uint32(id)) +func (k Keeper) GetCurrencyPairFromID(ctx context.Context, id uint64) (cp slinkytypes.CurrencyPair, found bool) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + mp, found := k.GetMarketParam(sdkCtx, uint32(id)) if !found { return cp, false } cp, err := slinky.MarketPairToCurrencyPair(mp.Pair) if err != nil { - k.Logger(ctx).Error("CurrencyPairFromString", "error", err) + k.Logger(sdkCtx).Error("CurrencyPairFromString", "error", err) return cp, false } return cp, true } -func (k Keeper) GetIDForCurrencyPair(ctx sdk.Context, cp slinkytypes.CurrencyPair) (uint64, bool) { +func (k Keeper) GetIDForCurrencyPair(ctx context.Context, cp slinkytypes.CurrencyPair) (uint64, bool) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + // Try to get corresponding market ID of the currency pair from the store - marketId, found := k.GetCurrencyPairIDFromStore(ctx, cp) + marketId, found := k.GetCurrencyPairIDFromStore(sdkCtx, cp) if found { return uint64(marketId), true } @@ -79,12 +84,15 @@ func (k Keeper) RemoveCurrencyPairFromStore(ctx sdk.Context, cp slinkytypes.Curr currencyPairIDStore.Delete([]byte(currencyPairString)) } -func (k Keeper) GetPriceForCurrencyPair(ctx sdk.Context, cp slinkytypes.CurrencyPair) (oracletypes.QuotePrice, error) { +func (k Keeper) GetPriceForCurrencyPair(ctx context.Context, cp slinkytypes.CurrencyPair) (oracletypes.QuotePrice, + error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + id, found := k.GetIDForCurrencyPair(ctx, cp) if !found { return oracletypes.QuotePrice{}, fmt.Errorf("currency pair %s not found", cp.String()) } - mp, err := k.GetMarketPrice(ctx, uint32(id)) + mp, err := k.GetMarketPrice(sdkCtx, uint32(id)) if err != nil { return oracletypes.QuotePrice{}, fmt.Errorf("currency pair %s not found", cp.String()) } @@ -93,8 +101,10 @@ func (k Keeper) GetPriceForCurrencyPair(ctx sdk.Context, cp slinkytypes.Currency }, nil } -func (k Keeper) GetNumCurrencyPairs(ctx sdk.Context) (uint64, error) { - marketPriceStore := k.getMarketPriceStore(ctx) +func (k Keeper) GetNumCurrencyPairs(ctx context.Context) (uint64, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + marketPriceStore := k.getMarketPriceStore(sdkCtx) var numMarketPrices uint64 @@ -111,12 +121,12 @@ func (k Keeper) GetNumCurrencyPairs(ctx sdk.Context) (uint64, error) { } // GetNumRemovedCurrencyPairs is currently a no-op since we don't support removing Markets right now. -func (k Keeper) GetNumRemovedCurrencyPairs(_ sdk.Context) (uint64, error) { +func (k Keeper) GetNumRemovedCurrencyPairs(_ context.Context) (uint64, error) { return 0, nil } // GetAllCurrencyPairs is not used with the DefaultCurrencyPair strategy. -// See https://github.com/skip-mev/slinky/blob/main/abci/strategies/currencypair/default.go -func (k Keeper) GetAllCurrencyPairs(ctx sdk.Context) []slinkytypes.CurrencyPair { +// See https://github.com/skip-mev/connect/v2/blob/main/abci/strategies/currencypair/default.go +func (k Keeper) GetAllCurrencyPairs(_ context.Context) []slinkytypes.CurrencyPair { return nil } diff --git a/protocol/x/prices/keeper/slinky_adapter_test.go b/protocol/x/prices/keeper/slinky_adapter_test.go index 36dedb8cd5..017a254899 100644 --- a/protocol/x/prices/keeper/slinky_adapter_test.go +++ b/protocol/x/prices/keeper/slinky_adapter_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - oracletypes "github.com/skip-mev/slinky/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/pkg/types" "github.com/stretchr/testify/require" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" diff --git a/protocol/x/prices/module_test.go b/protocol/x/prices/module_test.go index bc24360462..9ddcc5dc96 100644 --- a/protocol/x/prices/module_test.go +++ b/protocol/x/prices/module_test.go @@ -25,7 +25,7 @@ import ( prices_keeper "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" - marketmapkeeper "github.com/skip-mev/slinky/x/marketmap/keeper" + marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) diff --git a/protocol/x/prices/simulation/genesis.go b/protocol/x/prices/simulation/genesis.go index b29ea23bd0..370e4d945e 100644 --- a/protocol/x/prices/simulation/genesis.go +++ b/protocol/x/prices/simulation/genesis.go @@ -15,7 +15,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/lib/marketmap" "github.com/dydxprotocol/v4-chain/protocol/testutil/sim_helpers" "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" ) // genNumMarkets returns randomized num markets. diff --git a/protocol/x/prices/types/expected_keepers.go b/protocol/x/prices/types/expected_keepers.go index ea3f8fad98..3f725019ec 100644 --- a/protocol/x/prices/types/expected_keepers.go +++ b/protocol/x/prices/types/expected_keepers.go @@ -3,7 +3,7 @@ package types import ( "context" - marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" + marketmaptypes "github.com/skip-mev/connect/v2/x/marketmap/types" "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" @@ -32,8 +32,8 @@ type RevShareKeeper interface { // MarketMapKeeper defines the expected marketmap keeper used for simulations. type MarketMapKeeper interface { - GetAllMarkets(ctx sdk.Context) (map[string]marketmaptypes.Market, error) - GetMarket(ctx sdk.Context, tickerStr string) (marketmaptypes.Market, error) - EnableMarket(ctx sdk.Context, tickerStr string) error - DisableMarket(ctx sdk.Context, tickerStr string) error + GetAllMarkets(ctx context.Context) (map[string]marketmaptypes.Market, error) + GetMarket(ctx context.Context, tickerStr string) (marketmaptypes.Market, error) + EnableMarket(ctx context.Context, tickerStr string) error + DisableMarket(ctx context.Context, tickerStr string) error } diff --git a/protocol/x/prices/types/types.go b/protocol/x/prices/types/types.go index 1940a39ae6..87d9fec885 100644 --- a/protocol/x/prices/types/types.go +++ b/protocol/x/prices/types/types.go @@ -1,16 +1,18 @@ package types import ( + "context" + "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" - slinkytypes "github.com/skip-mev/slinky/pkg/types" - oracletypes "github.com/skip-mev/slinky/x/oracle/types" + slinkytypes "github.com/skip-mev/connect/v2/pkg/types" + oracletypes "github.com/skip-mev/connect/v2/x/oracle/types" ) type PricesKeeper interface { // Market related. CreateMarket( - ctx sdk.Context, + ctx context.Context, param MarketParam, price MarketPrice, ) (createdMarketParam MarketParam, err error) @@ -52,7 +54,7 @@ type PricesKeeper interface { AddCurrencyPairIDToStore(ctx sdk.Context, id uint32, cp slinkytypes.CurrencyPair) // Slinky compat - GetCurrencyPairFromID(ctx sdk.Context, id uint64) (cp slinkytypes.CurrencyPair, found bool) - GetIDForCurrencyPair(ctx sdk.Context, cp slinkytypes.CurrencyPair) (uint64, bool) - GetPriceForCurrencyPair(ctx sdk.Context, cp slinkytypes.CurrencyPair) (oracletypes.QuotePrice, error) + GetCurrencyPairFromID(ctx context.Context, id uint64) (cp slinkytypes.CurrencyPair, found bool) + GetIDForCurrencyPair(ctx context.Context, cp slinkytypes.CurrencyPair) (uint64, bool) + GetPriceForCurrencyPair(ctx context.Context, cp slinkytypes.CurrencyPair) (oracletypes.QuotePrice, error) } diff --git a/protocol/x/vault/keeper/orders.go b/protocol/x/vault/keeper/orders.go index 311bbbbe38..1129bb4651 100644 --- a/protocol/x/vault/keeper/orders.go +++ b/protocol/x/vault/keeper/orders.go @@ -45,7 +45,7 @@ func (k Keeper) RefreshAllVaultOrders(ctx sdk.Context) { vaultParams.QuotingParams = &defaultQuotingParams } vault := k.subaccountsKeeper.GetSubaccount(ctx, *vaultId.ToSubaccountId()) - if vault.PerpetualPositions == nil || len(vault.PerpetualPositions) == 0 { + if len(vault.PerpetualPositions) == 0 { if vault.GetUsdcPosition().Cmp(vaultParams.QuotingParams.ActivationThresholdQuoteQuantums.BigInt()) == -1 { continue } diff --git a/protocol/x/vest/types/vest_entry.go b/protocol/x/vest/types/vest_entry.go index b091be3aa5..65aa112099 100644 --- a/protocol/x/vest/types/vest_entry.go +++ b/protocol/x/vest/types/vest_entry.go @@ -7,15 +7,15 @@ import ( func (entry VestEntry) Validate() error { if entry.VesterAccount == "" { - return errorsmod.Wrapf(ErrInvalidVesterAccount, "vester account cannot be empty") + return errorsmod.Wrap(ErrInvalidVesterAccount, "vester account cannot be empty") } if entry.TreasuryAccount == "" { - return errorsmod.Wrapf(ErrInvalidTreasuryAccount, "treasury account cannot be empty") + return errorsmod.Wrap(ErrInvalidTreasuryAccount, "treasury account cannot be empty") } if err := sdk.ValidateDenom(entry.Denom); err != nil { - return errorsmod.Wrapf(ErrInvalidDenom, err.Error()) + return errorsmod.Wrap(ErrInvalidDenom, err.Error()) } if !entry.StartTime.Before(entry.EndTime) { @@ -23,11 +23,11 @@ func (entry VestEntry) Validate() error { } if entry.StartTime.Location().String() != "UTC" { - return errorsmod.Wrapf(ErrInvalidTimeZone, "start_time must be in UTC") + return errorsmod.Wrap(ErrInvalidTimeZone, "start_time must be in UTC") } if entry.EndTime.Location().String() != "UTC" { - return errorsmod.Wrapf(ErrInvalidTimeZone, "start_time must be in UTC") + return errorsmod.Wrap(ErrInvalidTimeZone, "start_time must be in UTC") } return nil } From f21b60d84a7bc2bad39a4347749507b73f208600 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Wed, 2 Oct 2024 15:42:21 -0400 Subject: [PATCH 066/120] Move FinalizeBlock event staging logic into a generic EventStager (#2435) --- protocol/finalizeblock/event_stager.go | 83 ++++++++++++++ .../streaming/full_node_streaming_manager.go | 107 +++++------------- protocol/streaming/noop_streaming_manager.go | 7 -- protocol/streaming/types/interface.go | 5 - protocol/x/clob/types/expected_keepers.go | 4 - protocol/x/subaccounts/keeper/subaccount.go | 16 --- protocol/x/subaccounts/types/types.go | 4 - 7 files changed, 113 insertions(+), 113 deletions(-) create mode 100644 protocol/finalizeblock/event_stager.go diff --git a/protocol/finalizeblock/event_stager.go b/protocol/finalizeblock/event_stager.go new file mode 100644 index 0000000000..cb8d7f2fa6 --- /dev/null +++ b/protocol/finalizeblock/event_stager.go @@ -0,0 +1,83 @@ +package finalizeblock + +import ( + "encoding/binary" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + ante_types "github.com/dydxprotocol/v4-chain/protocol/app/ante/types" + "github.com/dydxprotocol/v4-chain/protocol/lib" +) + +// EventStager supports staging and retrieval of events (of type T) from FinalizeBlock. +type EventStager[T proto.Message] struct { + transientStoreKey storetypes.StoreKey + cdc codec.BinaryCodec + stagedEventCountKey string + stagedEventKeyPrefix string +} + +// NewEventStager creates a new EventStager. +func NewEventStager[T proto.Message]( + transientStoreKey storetypes.StoreKey, + cdc codec.BinaryCodec, + stagedEventCountKey string, + stagedEventKeyPrefix string, +) EventStager[T] { + return EventStager[T]{ + transientStoreKey: transientStoreKey, + cdc: cdc, + stagedEventCountKey: stagedEventCountKey, + stagedEventKeyPrefix: stagedEventKeyPrefix, + } +} + +// GetStagedFinalizeBlockEvents retrieves all staged events from the store. +func (s EventStager[T]) GetStagedFinalizeBlockEvents( + ctx sdk.Context, + newStagedEvent func() T, +) []T { + noGasCtx := ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) + store := noGasCtx.TransientStore(s.transientStoreKey) + + count := s.getStagedEventsCount(store) + events := make([]T, count) + store = prefix.NewStore(store, []byte(s.stagedEventKeyPrefix)) + for i := uint32(0); i < count; i++ { + event := newStagedEvent() + bytes := store.Get(lib.Uint32ToKey(i)) + s.cdc.MustUnmarshal(bytes, event) + events[i] = event + } + return events +} + +func (s EventStager[T]) getStagedEventsCount( + store storetypes.KVStore, +) uint32 { + countsBytes := store.Get([]byte(s.stagedEventCountKey)) + if countsBytes == nil { + return 0 + } + return binary.BigEndian.Uint32(countsBytes) +} + +// StageFinalizeBlockEvent stages an event in the transient store. +func (s EventStager[T]) StageFinalizeBlockEvent( + ctx sdk.Context, + stagedEvent T, +) { + noGasCtx := ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) + store := noGasCtx.TransientStore(s.transientStoreKey) + + // Increment events count. + count := s.getStagedEventsCount(store) + store.Set([]byte(s.stagedEventCountKey), lib.Uint32ToKey(count+1)) + + // Store events keyed by index. + store = prefix.NewStore(store, []byte(s.stagedEventKeyPrefix)) + store.Set(lib.Uint32ToKey(count), s.cdc.MustMarshal(stagedEvent)) +} diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index 85c265f12e..f63beac347 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -1,7 +1,6 @@ package streaming import ( - "encoding/binary" "fmt" "sync" "sync/atomic" @@ -11,7 +10,6 @@ import ( satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "cosmossdk.io/log" - "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,6 +20,8 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ocutypes "github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates/types" + + "github.com/dydxprotocol/v4-chain/protocol/finalizeblock" ) var _ types.FullNodeStreamingManager = (*FullNodeStreamingManagerImpl)(nil) @@ -62,6 +62,8 @@ type FullNodeStreamingManagerImpl struct { // stores the staged FinalizeBlock events for full node streaming. streamingManagerTransientStoreKey storetypes.StoreKey + + finalizeBlockStager finalizeblock.EventStager[*clobtypes.StagedFinalizeBlockEvent] } // OrderbookSubscription represents a active subscription to the orderbook updates stream. @@ -119,6 +121,12 @@ func NewFullNodeStreamingManager( streamingManagerTransientStoreKey: streamingManagerTransientStoreKey, cdc: cdc, + finalizeBlockStager: finalizeblock.NewEventStager[*clobtypes.StagedFinalizeBlockEvent]( + streamingManagerTransientStoreKey, + cdc, + StagedEventsCountKey, + StagedEventsKeyPrefix, + ), } // Start the goroutine for pushing order updates through. @@ -381,14 +389,6 @@ func (sm *FullNodeStreamingManagerImpl) sendStreamUpdates( } } -func getStagedEventsCount(store storetypes.KVStore) uint32 { - countsBytes := store.Get([]byte(StagedEventsCountKey)) - if countsBytes == nil { - return 0 - } - return binary.BigEndian.Uint32(countsBytes) -} - // Send a subaccount update event. func (sm *FullNodeStreamingManagerImpl) SendSubaccountUpdate( ctx sdk.Context, @@ -405,51 +405,30 @@ func (sm *FullNodeStreamingManagerImpl) SendSubaccountUpdate( SubaccountUpdate: &subaccountUpdate, }, } - sm.stageFinalizeBlockEvent( + sm.finalizeBlockStager.StageFinalizeBlockEvent( ctx, - sm.cdc.MustMarshal(&stagedEvent), + &stagedEvent, ) } -func getStagedFinalizeBlockEventsFromStore( - store storetypes.KVStore, - cdc codec.BinaryCodec, -) []clobtypes.StagedFinalizeBlockEvent { - count := getStagedEventsCount(store) - events := make([]clobtypes.StagedFinalizeBlockEvent, count) - store = prefix.NewStore(store, []byte(StagedEventsKeyPrefix)) - for i := uint32(0); i < count; i++ { - var event clobtypes.StagedFinalizeBlockEvent - bytes := store.Get(lib.Uint32ToKey(i)) - cdc.MustUnmarshal(bytes, &event) - events[i] = event - } - return events -} - // Retrieve all events staged during `FinalizeBlock`. func (sm *FullNodeStreamingManagerImpl) GetStagedFinalizeBlockEvents( ctx sdk.Context, ) []clobtypes.StagedFinalizeBlockEvent { - noGasCtx := ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) - store := noGasCtx.TransientStore(sm.streamingManagerTransientStoreKey) - return getStagedFinalizeBlockEventsFromStore(store, sm.cdc) -} - -func (sm *FullNodeStreamingManagerImpl) stageFinalizeBlockEvent( - ctx sdk.Context, - eventBytes []byte, -) { - noGasCtx := ctx.WithGasMeter(ante_types.NewFreeInfiniteGasMeter()) - store := noGasCtx.TransientStore(sm.streamingManagerTransientStoreKey) - - // Increment events count. - count := getStagedEventsCount(store) - store.Set([]byte(StagedEventsCountKey), lib.Uint32ToKey(count+1)) - - // Store events keyed by index. - store = prefix.NewStore(store, []byte(StagedEventsKeyPrefix)) - store.Set(lib.Uint32ToKey(count), eventBytes) + events := sm.finalizeBlockStager.GetStagedFinalizeBlockEvents( + ctx, + func() *clobtypes.StagedFinalizeBlockEvent { + return &clobtypes.StagedFinalizeBlockEvent{} + }, + ) + results := make([]clobtypes.StagedFinalizeBlockEvent, len(events)) + for i, event := range events { + if event == nil { + panic("Got nil event from finalizeBlockStager") + } + results[i] = *event + } + return results } // SendCombinedSnapshot sends messages to a particular subscriber without buffering. @@ -574,9 +553,9 @@ func (sm *FullNodeStreamingManagerImpl) SendOrderbookUpdates( }, }, } - sm.stageFinalizeBlockEvent( + sm.finalizeBlockStager.StageFinalizeBlockEvent( ctx, - sm.cdc.MustMarshal(&stagedEvent), + &stagedEvent, ) } @@ -649,9 +628,9 @@ func (sm *FullNodeStreamingManagerImpl) SendOrderbookFillUpdate( }, } - sm.stageFinalizeBlockEvent( + sm.finalizeBlockStager.StageFinalizeBlockEvent( ctx, - sm.cdc.MustMarshal(&stagedEvent), + &stagedEvent, ) } @@ -710,32 +689,6 @@ func getStreamUpdatesForSubaccountUpdates( return streamUpdates, subaccountIds } -// SendFinalizedSubaccountUpdates groups subaccount updates by their subaccount ids and -// sends messages to the subscribers. -func (sm *FullNodeStreamingManagerImpl) SendFinalizedSubaccountUpdates( - subaccountUpdates []satypes.StreamSubaccountUpdate, - blockHeight uint32, - execMode sdk.ExecMode, -) { - defer metrics.ModuleMeasureSince( - metrics.FullNodeGrpc, - metrics.GrpcSendFinalizedSubaccountUpdatesLatency, - time.Now(), - ) - - if execMode != sdk.ExecModeFinalize { - panic("SendFinalizedSubaccountUpdates should only be called in ExecModeFinalize") - } - - streamUpdates, subaccountIds := getStreamUpdatesForSubaccountUpdates( - subaccountUpdates, - blockHeight, - execMode, - ) - - sm.AddSubaccountUpdatesToCache(streamUpdates, subaccountIds) -} - // AddOrderUpdatesToCache adds a series of updates to the full node streaming cache. // Clob pair ids are the clob pair id each update is relevant to. func (sm *FullNodeStreamingManagerImpl) AddOrderUpdatesToCache( diff --git a/protocol/streaming/noop_streaming_manager.go b/protocol/streaming/noop_streaming_manager.go index 9dc7bf6de9..89250854c4 100644 --- a/protocol/streaming/noop_streaming_manager.go +++ b/protocol/streaming/noop_streaming_manager.go @@ -48,13 +48,6 @@ func (sm *NoopGrpcStreamingManager) SendTakerOrderStatus( ) { } -func (sm *NoopGrpcStreamingManager) SendFinalizedSubaccountUpdates( - subaccountUpdates []satypes.StreamSubaccountUpdate, - blockHeight uint32, - execMode sdk.ExecMode, -) { -} - func (sm *NoopGrpcStreamingManager) TracksSubaccountId(id satypes.SubaccountId) bool { return false } diff --git a/protocol/streaming/types/interface.go b/protocol/streaming/types/interface.go index 5b42864016..33907fc1ec 100644 --- a/protocol/streaming/types/interface.go +++ b/protocol/streaming/types/interface.go @@ -42,11 +42,6 @@ type FullNodeStreamingManager interface { takerOrder clobtypes.StreamTakerOrder, ctx sdk.Context, ) - SendFinalizedSubaccountUpdates( - subaccountUpdates []satypes.StreamSubaccountUpdate, - blockHeight uint32, - execMode sdk.ExecMode, - ) SendSubaccountUpdate( ctx sdk.Context, subaccountUpdate satypes.StreamSubaccountUpdate, diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index 05e25e2521..846cc7d539 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -87,10 +87,6 @@ type SubaccountsKeeper interface { revSharesForFill revsharetypes.RevSharesForFill, fillForProcess FillForProcess, ) error - SendFinalizedSubaccountUpdates( - ctx sdk.Context, - subaccountUpdates []satypes.StreamSubaccountUpdate, - ) } type AssetsKeeper interface { diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index e72ccd60e7..52d4c05bb3 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -825,19 +825,3 @@ func (k Keeper) GetAllRelevantPerpetuals( func (k Keeper) GetFullNodeStreamingManager() streamingtypes.FullNodeStreamingManager { return k.streamingManager } - -// SendFinalizedSubaccountUpdates sends the subaccount updates to the gRPC streaming manager. -func (k Keeper) SendFinalizedSubaccountUpdates( - ctx sdk.Context, - subaccountUpdates []types.StreamSubaccountUpdate, -) { - lib.AssertDeliverTxMode(ctx) - if len(subaccountUpdates) == 0 { - return - } - k.GetFullNodeStreamingManager().SendFinalizedSubaccountUpdates( - subaccountUpdates, - lib.MustConvertIntegerToUint32(ctx.BlockHeight()), - ctx.ExecMode(), - ) -} diff --git a/protocol/x/subaccounts/types/types.go b/protocol/x/subaccounts/types/types.go index cbccc9d2b9..3e180d05c3 100644 --- a/protocol/x/subaccounts/types/types.go +++ b/protocol/x/subaccounts/types/types.go @@ -77,8 +77,4 @@ type SubaccountsKeeper interface { perpetualId uint32, blockHeight uint32, ) error - SendFinalizedSubaccountUpdates( - ctx sdk.Context, - subaccountUpdates []StreamSubaccountUpdate, - ) } From 8e90738db865885325053c60cc709925378501ad Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Wed, 2 Oct 2024 16:24:50 -0400 Subject: [PATCH 067/120] Update GetAllRevshare to handle liquidations (#2413) --- protocol/x/affiliates/abci.go | 5 +- .../x/clob/keeper/process_single_match.go | 2 +- protocol/x/revshare/keeper/revshare.go | 10 +- protocol/x/revshare/keeper/revshare_test.go | 118 ++++++++++++++++++ protocol/x/revshare/types/errors.go | 4 +- 5 files changed, 130 insertions(+), 9 deletions(-) diff --git a/protocol/x/affiliates/abci.go b/protocol/x/affiliates/abci.go index ccffe2ff8e..90063b492f 100644 --- a/protocol/x/affiliates/abci.go +++ b/protocol/x/affiliates/abci.go @@ -1,8 +1,6 @@ package affiliates import ( - "runtime/debug" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dydxprotocol/v4-chain/protocol/lib/log" "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/keeper" @@ -13,7 +11,6 @@ func EndBlocker( keeper *keeper.Keeper, ) { if err := keeper.AggregateAffiliateReferredVolumeForFills(ctx); err != nil { - log.ErrorLog(ctx, "error aggregating affiliate volume for fills", "error", - err, "stack", string(debug.Stack())) + log.ErrorLogWithError(ctx, "error aggregating affiliate volume for fills", err) } } diff --git a/protocol/x/clob/keeper/process_single_match.go b/protocol/x/clob/keeper/process_single_match.go index 903e351928..c2e504ea72 100644 --- a/protocol/x/clob/keeper/process_single_match.go +++ b/protocol/x/clob/keeper/process_single_match.go @@ -467,7 +467,7 @@ func (k Keeper) persistMatchedOrders( revSharesForFill, err := k.revshareKeeper.GetAllRevShares(ctx, fillForProcess, affiliatesWhitelistMap) if err != nil { revSharesForFill = revsharetypes.RevSharesForFill{} - log.ErrorLog(ctx, "error getting rev shares for fill", "error", err) + log.ErrorLogWithError(ctx, "error getting rev shares for fill", err) } if revSharesForFill.AffiliateRevShare != nil { affiliateRevSharesQuoteQuantums = revSharesForFill.AffiliateRevShare.QuoteQuantums diff --git a/protocol/x/revshare/keeper/revshare.go b/protocol/x/revshare/keeper/revshare.go index a842083791..b249e30fca 100644 --- a/protocol/x/revshare/keeper/revshare.go +++ b/protocol/x/revshare/keeper/revshare.go @@ -175,13 +175,18 @@ func (k Keeper) GetAllRevShares( makerFees := fill.MakerFeeQuoteQuantums netFees := big.NewInt(0).Add(takerFees, makerFees) + // when net fee is zero, no rev share is generated from the fill + if netFees.Sign() == 0 { + return types.RevSharesForFill{}, nil + } + affiliateRevShares, affiliateFeesShared, err := k.getAffiliateRevShares(ctx, fill, affiliatesWhitelistMap) if err != nil { return types.RevSharesForFill{}, err } netFeesSubAffiliateFeesShared := new(big.Int).Sub(netFees, affiliateFeesShared) if netFeesSubAffiliateFeesShared.Sign() <= 0 { - return types.RevSharesForFill{}, types.ErrAffiliateFeesSharedExceedsNetFees + return types.RevSharesForFill{}, types.ErrAffiliateFeesSharedGreaterThanOrEqualToNetFees } unconditionalRevShares, err := k.getUnconditionalRevShares(ctx, netFeesSubAffiliateFeesShared) @@ -233,7 +238,8 @@ func (k Keeper) getAffiliateRevShares( ) ([]types.RevShare, *big.Int, error) { takerAddr := fill.TakerAddr takerFee := fill.TakerFeeQuoteQuantums - if fill.MonthlyRollingTakerVolumeQuantums >= types.MaxReferee30dVolumeForAffiliateShareQuantums { + if fill.MonthlyRollingTakerVolumeQuantums >= types.MaxReferee30dVolumeForAffiliateShareQuantums || + takerFee.Sign() == 0 { return nil, big.NewInt(0), nil } diff --git a/protocol/x/revshare/keeper/revshare_test.go b/protocol/x/revshare/keeper/revshare_test.go index 23f2c2422f..d49c46ea75 100644 --- a/protocol/x/revshare/keeper/revshare_test.go +++ b/protocol/x/revshare/keeper/revshare_test.go @@ -726,6 +726,124 @@ func TestKeeper_GetAllRevShares_Valid(t *testing.T) { affiliatesKeeper *affiliateskeeper.Keeper) { }, }, + { + name: "Revshares with 0 fees from maker and taker", + expectedRevSharesForFill: types.RevSharesForFill{}, + fill: clobtypes.FillForProcess{ + TakerAddr: constants.AliceAccAddress.String(), + TakerFeeQuoteQuantums: big.NewInt(0), + MakerAddr: constants.BobAccAddress.String(), + MakerFeeQuoteQuantums: big.NewInt(0), + FillQuoteQuantums: big.NewInt(100_000_000_000), + ProductId: perpetualId, + MonthlyRollingTakerVolumeQuantums: 1_000_000_000_000, + MarketId: marketId, + }, + setup: func(tApp *testapp.TestApp, ctx sdk.Context, keeper *keeper.Keeper, + affiliatesKeeper *affiliateskeeper.Keeper) { + err := keeper.SetMarketMapperRevenueShareParams(ctx, types.MarketMapperRevenueShareParams{ + Address: constants.AliceAccAddress.String(), + RevenueSharePpm: 100_000, // 10% + ValidDays: 1, + }) + require.NoError(t, err) + + keeper.SetUnconditionalRevShareConfigParams(ctx, types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.BobAccAddress.String(), + SharePpm: 200_000, // 20% + }, + { + Address: constants.AliceAccAddress.String(), + SharePpm: 300_000, // 30% + }, + }, + }) + + err = affiliatesKeeper.UpdateAffiliateTiers(ctx, affiliatetypes.DefaultAffiliateTiers) + require.NoError(t, err) + err = affiliatesKeeper.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), + constants.BobAccAddress.String()) + require.NoError(t, err) + }, + }, + { + name: "Valid revenue share with 0 taker fee and positive maker fees", + expectedRevSharesForFill: types.RevSharesForFill{ + AllRevShares: []types.RevShare{ + { + Recipient: constants.BobAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(400_000), + RevSharePpm: 200_000, + }, + { + Recipient: constants.AliceAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_UNCONDITIONAL, + QuoteQuantums: big.NewInt(600_000), + RevSharePpm: 300_000, + }, + { + Recipient: constants.AliceAccAddress.String(), + RevShareFeeSource: types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE, + RevShareType: types.REV_SHARE_TYPE_MARKET_MAPPER, + QuoteQuantums: big.NewInt(200_000), + RevSharePpm: 100_000, + }, + }, + AffiliateRevShare: nil, + FeeSourceToQuoteQuantums: map[types.RevShareFeeSource]*big.Int{ + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: big.NewInt(0), + // unconditional + market mapper rev shares fees + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: big.NewInt(1_200_000), + }, + FeeSourceToRevSharePpm: map[types.RevShareFeeSource]uint32{ + types.REV_SHARE_FEE_SOURCE_TAKER_FEE: 0, + types.REV_SHARE_FEE_SOURCE_NET_PROTOCOL_REVENUE: 600_000, + }, + }, + fill: clobtypes.FillForProcess{ + TakerAddr: constants.AliceAccAddress.String(), + TakerFeeQuoteQuantums: big.NewInt(0), + MakerAddr: constants.BobAccAddress.String(), + MakerFeeQuoteQuantums: big.NewInt(2_000_000), + FillQuoteQuantums: big.NewInt(100_000_000_000), + ProductId: perpetualId, + MonthlyRollingTakerVolumeQuantums: 1_000_000_000_000, + MarketId: marketId, + }, + setup: func(tApp *testapp.TestApp, ctx sdk.Context, keeper *keeper.Keeper, + affiliatesKeeper *affiliateskeeper.Keeper) { + err := keeper.SetMarketMapperRevenueShareParams(ctx, types.MarketMapperRevenueShareParams{ + Address: constants.AliceAccAddress.String(), + RevenueSharePpm: 100_000, // 10% + ValidDays: 1, + }) + require.NoError(t, err) + + keeper.SetUnconditionalRevShareConfigParams(ctx, types.UnconditionalRevShareConfig{ + Configs: []types.UnconditionalRevShareConfig_RecipientConfig{ + { + Address: constants.BobAccAddress.String(), + SharePpm: 200_000, // 20% + }, + { + Address: constants.AliceAccAddress.String(), + SharePpm: 300_000, // 30% + }, + }, + }) + + err = affiliatesKeeper.UpdateAffiliateTiers(ctx, affiliatetypes.DefaultAffiliateTiers) + require.NoError(t, err) + err = affiliatesKeeper.RegisterAffiliate(ctx, constants.AliceAccAddress.String(), + constants.BobAccAddress.String()) + require.NoError(t, err) + }, + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/protocol/x/revshare/types/errors.go b/protocol/x/revshare/types/errors.go index 702ae92d15..e270cce323 100644 --- a/protocol/x/revshare/types/errors.go +++ b/protocol/x/revshare/types/errors.go @@ -36,9 +36,9 @@ var ( 6, "total fees shared exceeds net fees", ) - ErrAffiliateFeesSharedExceedsNetFees = errorsmod.Register( + ErrAffiliateFeesSharedGreaterThanOrEqualToNetFees = errorsmod.Register( ModuleName, 7, - "affiliate fees shared exceeds net fees", + "affiliate fees shared greater than or equal to net fees", ) ) From 46b55e229503d624c1c2ce204163076e2d465c8d Mon Sep 17 00:00:00 2001 From: Tian Date: Wed, 2 Oct 2024 17:24:19 -0400 Subject: [PATCH 068/120] remove deprecated params from x/vault params query (#2387) --- .../src/codegen/dydxprotocol/vault/query.ts | 26 +- proto/dydxprotocol/vault/query.proto | 6 +- protocol/x/vault/types/query.pb.go | 245 +++++++----------- 3 files changed, 101 insertions(+), 176 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.ts index bd8ced867f..0d2f16b855 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.ts @@ -1,7 +1,7 @@ import { VaultType, VaultTypeSDKType, VaultId, VaultIdSDKType } from "./vault"; import { PageRequest, PageRequestSDKType, PageResponse, PageResponseSDKType } from "../../cosmos/base/query/v1beta1/pagination"; import { NumShares, NumSharesSDKType, ShareUnlock, ShareUnlockSDKType, OwnerShare, OwnerShareSDKType } from "./share"; -import { Params, ParamsSDKType, QuotingParams, QuotingParamsSDKType, OperatorParams, OperatorParamsSDKType, VaultParams, VaultParamsSDKType } from "./params"; +import { QuotingParams, QuotingParamsSDKType, OperatorParams, OperatorParamsSDKType, VaultParams, VaultParamsSDKType } from "./params"; import { SubaccountId, SubaccountIdSDKType } from "../subaccounts/subaccount"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; @@ -14,20 +14,12 @@ export interface QueryParamsRequestSDKType {} /** QueryParamsResponse is a response type for the Params RPC method. */ export interface QueryParamsResponse { - /** Deprecated since v6.x in favor of default_quoting_params. */ - - /** @deprecated */ - params?: Params; defaultQuotingParams?: QuotingParams; operatorParams?: OperatorParams; } /** QueryParamsResponse is a response type for the Params RPC method. */ export interface QueryParamsResponseSDKType { - /** Deprecated since v6.x in favor of default_quoting_params. */ - - /** @deprecated */ - params?: ParamsSDKType; default_quoting_params?: QuotingParamsSDKType; operator_params?: OperatorParamsSDKType; } @@ -344,7 +336,6 @@ export const QueryParamsRequest = { function createBaseQueryParamsResponse(): QueryParamsResponse { return { - params: undefined, defaultQuotingParams: undefined, operatorParams: undefined }; @@ -352,16 +343,12 @@ function createBaseQueryParamsResponse(): QueryParamsResponse { export const QueryParamsResponse = { encode(message: QueryParamsResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.params !== undefined) { - Params.encode(message.params, writer.uint32(10).fork()).ldelim(); - } - if (message.defaultQuotingParams !== undefined) { - QuotingParams.encode(message.defaultQuotingParams, writer.uint32(18).fork()).ldelim(); + QuotingParams.encode(message.defaultQuotingParams, writer.uint32(10).fork()).ldelim(); } if (message.operatorParams !== undefined) { - OperatorParams.encode(message.operatorParams, writer.uint32(26).fork()).ldelim(); + OperatorParams.encode(message.operatorParams, writer.uint32(18).fork()).ldelim(); } return writer; @@ -377,14 +364,10 @@ export const QueryParamsResponse = { switch (tag >>> 3) { case 1: - message.params = Params.decode(reader, reader.uint32()); - break; - - case 2: message.defaultQuotingParams = QuotingParams.decode(reader, reader.uint32()); break; - case 3: + case 2: message.operatorParams = OperatorParams.decode(reader, reader.uint32()); break; @@ -399,7 +382,6 @@ export const QueryParamsResponse = { fromPartial(object: DeepPartial): QueryParamsResponse { const message = createBaseQueryParamsResponse(); - message.params = object.params !== undefined && object.params !== null ? Params.fromPartial(object.params) : undefined; message.defaultQuotingParams = object.defaultQuotingParams !== undefined && object.defaultQuotingParams !== null ? QuotingParams.fromPartial(object.defaultQuotingParams) : undefined; message.operatorParams = object.operatorParams !== undefined && object.operatorParams !== null ? OperatorParams.fromPartial(object.operatorParams) : undefined; return message; diff --git a/proto/dydxprotocol/vault/query.proto b/proto/dydxprotocol/vault/query.proto index a700529778..ed82af2013 100644 --- a/proto/dydxprotocol/vault/query.proto +++ b/proto/dydxprotocol/vault/query.proto @@ -61,10 +61,8 @@ message QueryParamsRequest {} // QueryParamsResponse is a response type for the Params RPC method. message QueryParamsResponse { - // Deprecated since v6.x in favor of default_quoting_params. - Params params = 1 [ (gogoproto.nullable) = false, deprecated = true ]; - QuotingParams default_quoting_params = 2 [ (gogoproto.nullable) = false ]; - OperatorParams operator_params = 3 [ (gogoproto.nullable) = false ]; + QuotingParams default_quoting_params = 1 [ (gogoproto.nullable) = false ]; + OperatorParams operator_params = 2 [ (gogoproto.nullable) = false ]; } // QueryVaultRequest is a request type for the Vault RPC method. diff --git a/protocol/x/vault/types/query.pb.go b/protocol/x/vault/types/query.pb.go index 59c0536601..228db44453 100644 --- a/protocol/x/vault/types/query.pb.go +++ b/protocol/x/vault/types/query.pb.go @@ -72,10 +72,8 @@ var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo // QueryParamsResponse is a response type for the Params RPC method. type QueryParamsResponse struct { - // Deprecated since v6.x in favor of default_quoting_params. - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // Deprecated: Do not use. - DefaultQuotingParams QuotingParams `protobuf:"bytes,2,opt,name=default_quoting_params,json=defaultQuotingParams,proto3" json:"default_quoting_params"` - OperatorParams OperatorParams `protobuf:"bytes,3,opt,name=operator_params,json=operatorParams,proto3" json:"operator_params"` + DefaultQuotingParams QuotingParams `protobuf:"bytes,1,opt,name=default_quoting_params,json=defaultQuotingParams,proto3" json:"default_quoting_params"` + OperatorParams OperatorParams `protobuf:"bytes,2,opt,name=operator_params,json=operatorParams,proto3" json:"operator_params"` } func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } @@ -111,14 +109,6 @@ func (m *QueryParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo -// Deprecated: Do not use. -func (m *QueryParamsResponse) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - func (m *QueryParamsResponse) GetDefaultQuotingParams() QuotingParams { if m != nil { return m.DefaultQuotingParams @@ -893,88 +883,88 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/vault/query.proto", fileDescriptor_478fb8dc0ff21ea6) } var fileDescriptor_478fb8dc0ff21ea6 = []byte{ - // 1295 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xc6, 0x89, 0x4b, 0x26, 0x49, 0x5b, 0x26, 0x69, 0xe2, 0xba, 0xc5, 0x49, 0x16, 0x68, - 0x9b, 0xb4, 0xf1, 0x92, 0x34, 0x6d, 0x11, 0x54, 0xa8, 0x09, 0xa2, 0x34, 0x48, 0xd0, 0x7a, 0x13, - 0x8a, 0x84, 0x04, 0xcb, 0xd8, 0x3b, 0x71, 0x56, 0xac, 0x77, 0x9c, 0xdd, 0xd9, 0x24, 0x26, 0x8a, - 0x84, 0x40, 0x1c, 0xb8, 0x21, 0x71, 0xe5, 0x02, 0x1f, 0x01, 0x21, 0x21, 0x0e, 0x1c, 0x10, 0x3d, - 0xf4, 0x58, 0xc1, 0x05, 0x71, 0xa8, 0x50, 0xc2, 0x99, 0xcf, 0x80, 0x76, 0xe6, 0xad, 0xbd, 0xeb, - 0xac, 0x9d, 0x6d, 0xe5, 0x5e, 0x22, 0xef, 0xcc, 0x7b, 0xbf, 0xdf, 0x7b, 0x6f, 0xde, 0xbf, 0xa0, - 0x82, 0xd9, 0x30, 0x77, 0xeb, 0x2e, 0xe3, 0xac, 0xc2, 0x6c, 0x6d, 0x9b, 0xf8, 0x36, 0xd7, 0xb6, - 0x7c, 0xea, 0x36, 0x8a, 0xe2, 0x10, 0xe3, 0xe8, 0x7d, 0x51, 0xdc, 0xe7, 0xcf, 0x56, 0x98, 0x57, - 0x63, 0x9e, 0x21, 0x8e, 0x35, 0xf9, 0x21, 0xc5, 0xf3, 0x73, 0xf2, 0x4b, 0x2b, 0x13, 0x8f, 0x4a, - 0x1c, 0x6d, 0x7b, 0xa1, 0x4c, 0x39, 0x59, 0xd0, 0xea, 0xa4, 0x6a, 0x39, 0x84, 0x5b, 0xcc, 0x01, - 0xd9, 0xf1, 0x2a, 0xab, 0x32, 0x89, 0x11, 0xfc, 0x82, 0xd3, 0xf3, 0x55, 0xc6, 0xaa, 0x36, 0xd5, - 0x48, 0xdd, 0xd2, 0x88, 0xe3, 0x30, 0x2e, 0x54, 0x42, 0xfc, 0xd9, 0x98, 0xb9, 0x9e, 0x5f, 0x26, - 0x95, 0x0a, 0xf3, 0x1d, 0xee, 0x45, 0x7e, 0x83, 0xe8, 0x54, 0x82, 0x67, 0x75, 0xe2, 0x92, 0x5a, - 0x88, 0x95, 0xe4, 0xba, 0xb7, 0x49, 0x5c, 0xda, 0xe5, 0x5e, 0xfc, 0x95, 0xf7, 0xea, 0x38, 0xc2, - 0xa5, 0xc0, 0xc3, 0x7b, 0x02, 0x54, 0xa7, 0x5b, 0x3e, 0xf5, 0xb8, 0xfa, 0x65, 0x3f, 0x1a, 0x8b, - 0x1d, 0x7b, 0x75, 0xe6, 0x78, 0x14, 0xbf, 0x86, 0xb2, 0x92, 0x3d, 0xa7, 0x4c, 0x2b, 0x97, 0x86, - 0x17, 0xf3, 0xc5, 0xa3, 0x91, 0x2d, 0x4a, 0x9d, 0x95, 0xec, 0xc3, 0xc7, 0x53, 0x7d, 0x39, 0x45, - 0x07, 0x0d, 0xfc, 0x11, 0x9a, 0x30, 0xe9, 0x46, 0x20, 0x61, 0x6c, 0xf9, 0x8c, 0x5b, 0x4e, 0xd5, - 0x00, 0xac, 0x7e, 0x81, 0x35, 0x93, 0x84, 0x55, 0x92, 0x92, 0x00, 0x39, 0x10, 0x40, 0xea, 0xe3, - 0x00, 0x13, 0xbb, 0xc3, 0x25, 0x74, 0x8a, 0xd5, 0xa9, 0x4b, 0x38, 0x73, 0x43, 0xdc, 0x8c, 0xc0, - 0x55, 0x93, 0x70, 0xef, 0x82, 0x68, 0x0c, 0xf8, 0x24, 0x8b, 0x9d, 0xaa, 0x1f, 0xa3, 0xe7, 0x45, - 0x10, 0xee, 0x07, 0x2a, 0x10, 0x1a, 0xbc, 0x80, 0x06, 0x78, 0xa3, 0x4e, 0x45, 0x00, 0x4e, 0x2e, - 0xbe, 0x90, 0x04, 0x2e, 0xe4, 0xd7, 0x1b, 0x75, 0xaa, 0x0b, 0x51, 0x3c, 0x81, 0xb2, 0x8e, 0x5f, - 0x2b, 0x53, 0x57, 0x78, 0x3a, 0xaa, 0xc3, 0x97, 0xfa, 0x5f, 0x06, 0x82, 0x0f, 0x04, 0x10, 0xe4, - 0x9b, 0xe8, 0x39, 0x81, 0x63, 0x58, 0x26, 0x84, 0xf9, 0x5c, 0x47, 0x96, 0x55, 0x13, 0x6c, 0x3f, - 0xb1, 0x2d, 0x3f, 0x71, 0x09, 0x8d, 0xb6, 0xb2, 0x28, 0x80, 0x90, 0xd1, 0xbd, 0x10, 0x87, 0x88, - 0x24, 0x5d, 0x71, 0xad, 0xf9, 0xbb, 0x89, 0x36, 0xe2, 0x45, 0xce, 0xf0, 0x27, 0x28, 0x4b, 0xb7, - 0x7c, 0x8b, 0x37, 0x44, 0x44, 0x47, 0x56, 0xee, 0x04, 0x32, 0x7f, 0x3f, 0x9e, 0xba, 0x55, 0xb5, - 0xf8, 0xa6, 0x5f, 0x2e, 0x56, 0x58, 0x4d, 0x8b, 0xa7, 0xd9, 0xd2, 0x7c, 0x65, 0x93, 0x58, 0x8e, - 0xd6, 0x3c, 0x31, 0x83, 0x40, 0x78, 0xc5, 0x35, 0xea, 0x5a, 0xc4, 0xb6, 0x3e, 0x23, 0x65, 0x9b, - 0xae, 0x3a, 0x5c, 0x07, 0x5c, 0xbc, 0x81, 0x86, 0x2c, 0x67, 0x9b, 0x3a, 0x9c, 0xb9, 0x8d, 0xdc, - 0x40, 0x8f, 0x49, 0x5a, 0xd0, 0xf8, 0x0e, 0x1a, 0x91, 0xa1, 0x85, 0x0c, 0x19, 0x14, 0xb1, 0x99, - 0xea, 0x18, 0xde, 0x58, 0x7a, 0x0c, 0x6f, 0xb7, 0x8e, 0xf0, 0x55, 0x34, 0x51, 0x63, 0x1e, 0x37, - 0x5c, 0x5a, 0xa1, 0x0e, 0x37, 0x2a, 0xb6, 0x45, 0x45, 0xb8, 0xbd, 0x5c, 0x76, 0x3a, 0x73, 0x69, - 0x54, 0x1f, 0x0b, 0x6e, 0x75, 0x71, 0xf9, 0xa6, 0xb8, 0x5b, 0x35, 0x3d, 0xd5, 0x40, 0x67, 0xc4, - 0x7b, 0x2f, 0xdb, 0xb6, 0x80, 0x0f, 0xeb, 0x0d, 0xdf, 0x46, 0xa8, 0xd5, 0x59, 0xe0, 0xd1, 0x2f, - 0x14, 0xa1, 0x29, 0x05, 0x6d, 0xa8, 0x28, 0xdb, 0x19, 0xb4, 0xa1, 0xe2, 0x3d, 0x52, 0xa5, 0xa0, - 0xab, 0x47, 0x34, 0xd5, 0xef, 0x15, 0x34, 0xd1, 0xce, 0x00, 0x59, 0xf5, 0x06, 0xca, 0x0a, 0xfb, - 0x83, 0xd2, 0xcd, 0x1c, 0x4d, 0x88, 0xb0, 0xdc, 0xda, 0xb3, 0x51, 0x07, 0x2d, 0xfc, 0x76, 0xcc, - 0x44, 0x99, 0x54, 0x17, 0x8f, 0x35, 0x11, 0x40, 0xa2, 0x36, 0xaa, 0x68, 0x5a, 0xd0, 0xbc, 0x4b, - 0xab, 0x44, 0x60, 0xaf, 0x33, 0x4e, 0xec, 0xb5, 0xa0, 0x67, 0x35, 0xfb, 0x0f, 0x45, 0x33, 0x5d, - 0x64, 0xc0, 0xa3, 0x5b, 0x68, 0x84, 0x07, 0xc7, 0x86, 0xe8, 0x77, 0x61, 0x4b, 0x4a, 0xac, 0xc8, - 0xf7, 0xfc, 0x1a, 0x28, 0x0f, 0xf3, 0x16, 0x92, 0x7a, 0xbf, 0xdd, 0x94, 0xbb, 0x3b, 0x0e, 0x75, - 0x63, 0xa6, 0xe0, 0x45, 0x74, 0x82, 0x98, 0xa6, 0x4b, 0x3d, 0x49, 0x30, 0xb4, 0x92, 0xfb, 0xe3, - 0xa7, 0xf9, 0x71, 0xf0, 0x7b, 0x59, 0xde, 0xac, 0x71, 0xd7, 0x72, 0xaa, 0x7a, 0x28, 0xa8, 0xfe, - 0x9a, 0x69, 0xb7, 0x3f, 0x06, 0x0c, 0xf6, 0x3f, 0x05, 0x32, 0x7e, 0x1d, 0x65, 0xc1, 0xdb, 0xfe, - 0x14, 0xde, 0x42, 0xe2, 0x82, 0x0a, 0x7e, 0x07, 0x8d, 0x8a, 0x5f, 0x86, 0xef, 0xd8, 0xac, 0xf2, - 0x69, 0xd0, 0x20, 0x33, 0x9d, 0xd2, 0x5f, 0x00, 0xbc, 0x2f, 0xe4, 0x9a, 0x3d, 0xa1, 0x75, 0xe4, - 0x45, 0x7a, 0xc2, 0xc0, 0x33, 0xea, 0x09, 0x0d, 0x34, 0xb6, 0x63, 0xf1, 0x4d, 0xd3, 0x25, 0x3b, - 0xc1, 0x95, 0x01, 0x74, 0x83, 0x3d, 0xa6, 0xc3, 0x51, 0x92, 0xb7, 0x04, 0x87, 0x5a, 0x43, 0x2f, - 0xc6, 0x9f, 0x6f, 0xd9, 0xb6, 0x13, 0x52, 0xa3, 0x57, 0x55, 0xfb, 0xa3, 0x82, 0x5e, 0xea, 0xce, - 0x07, 0x19, 0xb3, 0x8c, 0x46, 0x58, 0x70, 0xdc, 0xca, 0xf8, 0xe0, 0xfd, 0x0a, 0x89, 0x03, 0xae, - 0xa9, 0xae, 0x0f, 0xb3, 0x16, 0x54, 0xef, 0xca, 0xd8, 0x44, 0x93, 0xad, 0x6e, 0x11, 0xdb, 0x1e, - 0x7a, 0x39, 0x22, 0x7f, 0x50, 0x50, 0xee, 0x28, 0x4d, 0x4f, 0x06, 0x65, 0xfb, 0x2c, 0xe8, 0x7f, - 0xda, 0x59, 0xa0, 0xee, 0xb6, 0xa7, 0xcb, 0x07, 0x61, 0x4a, 0xd9, 0xab, 0xce, 0x06, 0x0b, 0xc3, - 0x52, 0x42, 0x58, 0xbe, 0x9b, 0xc1, 0x99, 0x11, 0x66, 0x5d, 0xaa, 0xae, 0x05, 0xa4, 0xa7, 0xa5, - 0xfa, 0x3a, 0x0b, 0xf1, 0xd5, 0x5f, 0x32, 0xed, 0x99, 0xd3, 0x4e, 0x0d, 0xa1, 0xea, 0x3d, 0x37, - 0xfe, 0x5c, 0x41, 0x93, 0x74, 0xb7, 0x4e, 0x2b, 0x9c, 0x9a, 0x62, 0xa3, 0xa3, 0xc6, 0x96, 0x4f, - 0x1c, 0xee, 0x43, 0x2c, 0x7b, 0x59, 0xa4, 0x67, 0x42, 0xa2, 0x60, 0xe7, 0xa3, 0x25, 0xa0, 0xc1, - 0x1e, 0x3a, 0x5d, 0x0b, 0x1d, 0x37, 0x9e, 0xd1, 0x8a, 0x72, 0xaa, 0xc9, 0x20, 0x9b, 0x03, 0xbe, - 0xdd, 0x36, 0x76, 0x06, 0xd2, 0x07, 0x31, 0x3a, 0x7c, 0x16, 0x1f, 0x20, 0x34, 0x28, 0xde, 0x0e, - 0xef, 0xa3, 0x2c, 0x6c, 0x15, 0x9d, 0x87, 0x72, 0xac, 0xc2, 0xf2, 0x17, 0x8f, 0x95, 0x93, 0xef, - 0xae, 0xaa, 0x5f, 0xfc, 0xf9, 0xef, 0xb7, 0xfd, 0xe7, 0x71, 0x5e, 0xeb, 0xf8, 0x8f, 0x04, 0xfe, - 0x5a, 0x41, 0x83, 0x22, 0xc3, 0xf1, 0xcb, 0xc7, 0xed, 0x04, 0x92, 0x3d, 0xe5, 0xea, 0xa0, 0x2e, - 0x08, 0xf2, 0xcb, 0x78, 0x56, 0xeb, 0xf4, 0x4f, 0x88, 0xb6, 0x17, 0x04, 0x7d, 0x5f, 0xdb, 0x93, - 0xe5, 0xbe, 0x8f, 0xbf, 0x52, 0xd0, 0x50, 0x73, 0x77, 0xc1, 0xb3, 0x1d, 0x89, 0xda, 0x37, 0xa8, - 0xfc, 0x5c, 0x1a, 0x51, 0xb0, 0x6b, 0x46, 0xd8, 0x75, 0x0e, 0x9f, 0xed, 0x68, 0x17, 0xfe, 0x59, - 0x41, 0xe3, 0x49, 0xcb, 0x07, 0x5e, 0xea, 0xc8, 0xd3, 0x65, 0x9f, 0xc9, 0x5f, 0x7b, 0x42, 0x2d, - 0x30, 0x74, 0x51, 0x18, 0x7a, 0x05, 0xcf, 0x25, 0x19, 0xda, 0xcc, 0x4b, 0x2d, 0x9a, 0x8e, 0xf8, - 0xb7, 0xa8, 0xe5, 0x91, 0x21, 0x92, 0xc6, 0xf2, 0xa3, 0x33, 0x2e, 0x8d, 0xe5, 0x09, 0x93, 0x4a, - 0xbd, 0x29, 0x2c, 0xbf, 0x8e, 0x97, 0xba, 0x5b, 0x1e, 0x9d, 0x66, 0xda, 0x1e, 0x2c, 0x39, 0xfb, - 0xf8, 0x81, 0x82, 0x26, 0x3b, 0xcc, 0x42, 0x7c, 0xe3, 0x78, 0x83, 0x12, 0xa7, 0x75, 0xfe, 0xd5, - 0x27, 0x57, 0x04, 0x67, 0xae, 0x0b, 0x67, 0x5e, 0xc1, 0xc5, 0xee, 0xce, 0x10, 0xdb, 0x36, 0xa2, - 0x0e, 0xe1, 0xef, 0x14, 0x34, 0x1c, 0x19, 0x1d, 0xf8, 0x72, 0xf7, 0xba, 0x89, 0x97, 0xf8, 0x95, - 0x74, 0xc2, 0x69, 0x32, 0x45, 0xd6, 0xf9, 0x91, 0x5a, 0xfb, 0x3d, 0x1a, 0xe5, 0xf8, 0xdc, 0x48, - 0x13, 0xe5, 0xc4, 0x21, 0x97, 0x26, 0xca, 0xc9, 0x23, 0x4a, 0xbd, 0x26, 0x5c, 0xd0, 0xf0, 0x7c, - 0xf7, 0x28, 0x37, 0xd7, 0x35, 0xdb, 0xb0, 0x9c, 0x0d, 0xb6, 0x52, 0x7a, 0x78, 0x50, 0x50, 0x1e, - 0x1d, 0x14, 0x94, 0x7f, 0x0e, 0x0a, 0xca, 0x37, 0x87, 0x85, 0xbe, 0x47, 0x87, 0x85, 0xbe, 0xbf, - 0x0e, 0x0b, 0x7d, 0x1f, 0xde, 0x48, 0xdf, 0xfb, 0x77, 0x81, 0x46, 0x8c, 0x80, 0x72, 0x56, 0x9c, - 0x5f, 0xfd, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x49, 0x93, 0xca, 0x9a, 0x57, 0x12, 0x00, 0x00, + // 1282 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, + 0x17, 0xcf, 0xc6, 0x89, 0xfb, 0xcd, 0x4b, 0xd2, 0xf6, 0x3b, 0x49, 0x13, 0xd7, 0x2d, 0x4e, 0xb2, + 0x40, 0x9b, 0xa4, 0x8d, 0x97, 0xa4, 0x69, 0x8b, 0x44, 0x85, 0x9a, 0x20, 0x4a, 0x83, 0x04, 0xad, + 0x37, 0xa1, 0x48, 0x48, 0xb0, 0x8c, 0xbd, 0x13, 0x67, 0xc5, 0x7a, 0xc7, 0xd9, 0x9d, 0x4d, 0x62, + 0xa2, 0x48, 0x08, 0x89, 0x03, 0x37, 0x24, 0xae, 0x5c, 0xe0, 0x4f, 0x40, 0x48, 0x88, 0x03, 0x07, + 0x44, 0x25, 0x7a, 0xac, 0xe0, 0x82, 0x38, 0x54, 0x28, 0xe1, 0xcc, 0xdf, 0x80, 0x76, 0x66, 0xd6, + 0xde, 0x75, 0xd6, 0xce, 0xb6, 0x72, 0x2f, 0x91, 0x77, 0xe6, 0xbd, 0xcf, 0xfb, 0xbc, 0x37, 0xef, + 0x57, 0xa0, 0x60, 0x36, 0xcc, 0xbd, 0xba, 0x4b, 0x19, 0xad, 0x50, 0x5b, 0xdb, 0xc1, 0xbe, 0xcd, + 0xb4, 0x6d, 0x9f, 0xb8, 0x8d, 0x22, 0x3f, 0x44, 0x28, 0x7a, 0x5f, 0xe4, 0xf7, 0xf9, 0xf3, 0x15, + 0xea, 0xd5, 0xa8, 0x67, 0xf0, 0x63, 0x4d, 0x7c, 0x08, 0xf1, 0xfc, 0xbc, 0xf8, 0xd2, 0xca, 0xd8, + 0x23, 0x02, 0x47, 0xdb, 0x59, 0x2c, 0x13, 0x86, 0x17, 0xb5, 0x3a, 0xae, 0x5a, 0x0e, 0x66, 0x16, + 0x75, 0xa4, 0xec, 0x78, 0x95, 0x56, 0xa9, 0xc0, 0x08, 0x7e, 0xc9, 0xd3, 0x8b, 0x55, 0x4a, 0xab, + 0x36, 0xd1, 0x70, 0xdd, 0xd2, 0xb0, 0xe3, 0x50, 0xc6, 0x55, 0x42, 0xfc, 0xb9, 0x18, 0x5d, 0xcf, + 0x2f, 0xe3, 0x4a, 0x85, 0xfa, 0x0e, 0xf3, 0x22, 0xbf, 0xa5, 0xe8, 0x54, 0x82, 0x67, 0x75, 0xec, + 0xe2, 0x5a, 0x88, 0x95, 0xe4, 0xba, 0xb7, 0x85, 0x5d, 0xd2, 0xe5, 0x9e, 0xff, 0x15, 0xf7, 0xea, + 0x38, 0xa0, 0x52, 0xe0, 0xe1, 0x7d, 0x0e, 0xaa, 0x93, 0x6d, 0x9f, 0x78, 0x4c, 0xfd, 0x4d, 0x81, + 0xb1, 0xd8, 0xb1, 0x57, 0xa7, 0x8e, 0x47, 0xd0, 0x87, 0x30, 0x61, 0x92, 0xcd, 0x40, 0xdd, 0xd8, + 0xf6, 0x29, 0xb3, 0x9c, 0xaa, 0x21, 0xd8, 0xe4, 0x94, 0x69, 0x65, 0x76, 0x78, 0x69, 0xa6, 0x78, + 0x3c, 0xd2, 0xc5, 0x92, 0x90, 0x14, 0x50, 0xab, 0x03, 0x8f, 0x9e, 0x4c, 0xf5, 0xe9, 0xe3, 0x12, + 0x26, 0x76, 0x87, 0x4a, 0x70, 0x86, 0xd6, 0x89, 0x8b, 0x19, 0x75, 0x43, 0xdc, 0x7e, 0x8e, 0xab, + 0x26, 0xe1, 0xde, 0x93, 0xa2, 0x31, 0xe0, 0xd3, 0x34, 0x76, 0xaa, 0x7e, 0x04, 0xff, 0xe7, 0x8e, + 0x3c, 0x08, 0x54, 0xa4, 0x7b, 0x68, 0x11, 0x06, 0x58, 0xa3, 0x4e, 0x38, 0xe9, 0xd3, 0x4b, 0x2f, + 0x24, 0x81, 0x73, 0xf9, 0x8d, 0x46, 0x9d, 0xe8, 0x5c, 0x14, 0x4d, 0x40, 0xd6, 0xf1, 0x6b, 0x65, + 0xe2, 0x72, 0x46, 0xa3, 0xba, 0xfc, 0x52, 0xff, 0xcd, 0xc8, 0x00, 0x4a, 0x03, 0x32, 0x50, 0xb7, + 0xe0, 0x7f, 0x1c, 0xc7, 0xb0, 0x4c, 0x19, 0x9a, 0x0b, 0x1d, 0xad, 0xac, 0x99, 0x92, 0xfb, 0xa9, + 0x1d, 0xf1, 0x89, 0x4a, 0x30, 0xda, 0xca, 0x84, 0x00, 0x42, 0x44, 0xe1, 0x52, 0x1c, 0x22, 0x92, + 0x38, 0xc5, 0xf5, 0xe6, 0xef, 0x26, 0xda, 0x88, 0x17, 0x39, 0x43, 0x1f, 0x43, 0x96, 0x6c, 0xfb, + 0x16, 0x6b, 0xe4, 0x32, 0xd3, 0xca, 0xec, 0xc8, 0xea, 0xdd, 0x40, 0xe6, 0xaf, 0x27, 0x53, 0xb7, + 0xab, 0x16, 0xdb, 0xf2, 0xcb, 0xc5, 0x0a, 0xad, 0x69, 0xf1, 0x54, 0x59, 0x5e, 0xa8, 0x6c, 0x61, + 0xcb, 0xd1, 0x9a, 0x27, 0x66, 0x10, 0x08, 0xaf, 0xb8, 0x4e, 0x5c, 0x0b, 0xdb, 0xd6, 0xa7, 0xb8, + 0x6c, 0x93, 0x35, 0x87, 0xe9, 0x12, 0x17, 0x6d, 0xc2, 0x90, 0xe5, 0xec, 0x10, 0x87, 0x51, 0xb7, + 0x91, 0x1b, 0xe8, 0xb1, 0x91, 0x16, 0x34, 0xba, 0x0b, 0x23, 0x22, 0xb4, 0x32, 0x43, 0x06, 0x79, + 0x6c, 0xa6, 0x3a, 0x86, 0x37, 0x96, 0x1e, 0xc3, 0x3b, 0xad, 0x23, 0x74, 0x0d, 0x26, 0x6a, 0xd4, + 0x63, 0x86, 0x4b, 0x2a, 0xc4, 0x61, 0x46, 0xc5, 0xb6, 0x08, 0x0f, 0xb7, 0x97, 0xcb, 0x4e, 0x67, + 0x66, 0x47, 0xf5, 0xb1, 0xe0, 0x56, 0xe7, 0x97, 0x6f, 0xf0, 0xbb, 0x35, 0xd3, 0x53, 0x0d, 0x38, + 0xc7, 0xdf, 0x7b, 0xc5, 0xb6, 0x39, 0x7c, 0x58, 0x33, 0xe8, 0x0e, 0x40, 0xab, 0x3b, 0xc8, 0x47, + 0xbf, 0x54, 0x94, 0x8d, 0x25, 0x68, 0x25, 0x45, 0xd1, 0x92, 0x64, 0x2b, 0x29, 0xde, 0xc7, 0x55, + 0x22, 0x75, 0xf5, 0x88, 0xa6, 0xfa, 0xad, 0x02, 0x13, 0xed, 0x16, 0x64, 0x56, 0xbd, 0x0e, 0x59, + 0xce, 0x3f, 0x28, 0xb7, 0xcc, 0xf1, 0x84, 0x08, 0xcb, 0xad, 0x3d, 0x1b, 0x75, 0xa9, 0x85, 0xde, + 0x8a, 0x51, 0x14, 0x49, 0x75, 0xf9, 0x44, 0x8a, 0x12, 0x24, 0xca, 0x51, 0x85, 0x69, 0x6e, 0xe6, + 0x1d, 0x52, 0xc5, 0x1c, 0x7b, 0x83, 0x32, 0x6c, 0xaf, 0x07, 0x7d, 0xa7, 0xd9, 0x43, 0x08, 0xcc, + 0x74, 0x91, 0x91, 0x1e, 0xdd, 0x86, 0x11, 0x16, 0x1c, 0x1b, 0xbc, 0x67, 0x85, 0x6d, 0x24, 0xb1, + 0x22, 0xdf, 0xf5, 0x6b, 0x52, 0x79, 0x98, 0xb5, 0x90, 0xd4, 0x07, 0xed, 0x54, 0xee, 0xed, 0x3a, + 0xc4, 0x8d, 0x51, 0x41, 0x4b, 0x70, 0x0a, 0x9b, 0xa6, 0x4b, 0x3c, 0x61, 0x60, 0x68, 0x35, 0xf7, + 0xfb, 0x0f, 0x0b, 0xe3, 0xd2, 0xef, 0x15, 0x71, 0xb3, 0xce, 0x5c, 0xcb, 0xa9, 0xea, 0xa1, 0xa0, + 0xfa, 0x73, 0xa6, 0x9d, 0x7f, 0x0c, 0x58, 0xf2, 0x7f, 0x06, 0x64, 0xf4, 0x1a, 0x64, 0xa5, 0xb7, + 0xfd, 0x29, 0xbc, 0x95, 0x89, 0x2b, 0x55, 0xd0, 0xdb, 0x30, 0xca, 0x7f, 0x19, 0xbe, 0x63, 0xd3, + 0xca, 0x27, 0x5e, 0x2e, 0xc3, 0x33, 0x21, 0x31, 0xfd, 0x39, 0xc0, 0x7b, 0x5c, 0xae, 0xd9, 0x13, + 0x5a, 0x47, 0x5e, 0xa4, 0x27, 0x0c, 0x3c, 0xa7, 0x9e, 0xd0, 0x80, 0xb1, 0x5d, 0x8b, 0x6d, 0x99, + 0x2e, 0xde, 0x0d, 0xae, 0x0c, 0x69, 0x6e, 0xb0, 0xc7, 0xe6, 0x50, 0xd4, 0xc8, 0x9b, 0xdc, 0x86, + 0x5a, 0x83, 0x17, 0xe3, 0xcf, 0xb7, 0x62, 0xdb, 0x09, 0xa9, 0xd1, 0xab, 0xaa, 0xfd, 0x5e, 0x81, + 0x97, 0xba, 0xdb, 0x93, 0x19, 0xb3, 0x02, 0x23, 0x34, 0x38, 0x6e, 0x65, 0x7c, 0xf0, 0x7e, 0x85, + 0xc4, 0x01, 0xd7, 0x54, 0xd7, 0x87, 0x69, 0x0b, 0xaa, 0x77, 0x65, 0x6c, 0xc2, 0x64, 0xab, 0x5b, + 0xc4, 0x36, 0x80, 0x5e, 0x8e, 0xc8, 0xef, 0x14, 0xc8, 0x1d, 0x37, 0xd3, 0x93, 0x41, 0xd9, 0x3e, + 0x0b, 0xfa, 0x9f, 0x75, 0x16, 0xa8, 0x7b, 0xed, 0xe9, 0xf2, 0x7e, 0x98, 0x52, 0xf6, 0x9a, 0xb3, + 0x49, 0xc3, 0xb0, 0x94, 0x00, 0x89, 0x77, 0x33, 0x18, 0x35, 0xc2, 0xac, 0x4b, 0xd5, 0xb5, 0xa4, + 0xd1, 0xb3, 0x42, 0x7d, 0x83, 0x86, 0xf8, 0xea, 0x4f, 0x99, 0xf6, 0xcc, 0x69, 0x37, 0x2d, 0x43, + 0xd5, 0x7b, 0xdb, 0xe8, 0x33, 0x05, 0x26, 0xc9, 0x5e, 0x9d, 0x54, 0x18, 0x31, 0xf9, 0x46, 0x47, + 0x8c, 0x6d, 0x1f, 0x3b, 0xcc, 0x97, 0xb1, 0xec, 0x65, 0x91, 0x9e, 0x0b, 0x0d, 0x05, 0x3b, 0x1f, + 0x29, 0x49, 0x33, 0xc8, 0x83, 0xb3, 0xb5, 0xd0, 0x71, 0xe3, 0x39, 0xad, 0x28, 0x67, 0x9a, 0x16, + 0x44, 0x73, 0x40, 0x77, 0xda, 0xc6, 0xce, 0x40, 0xfa, 0x20, 0x46, 0x87, 0xcf, 0xd2, 0x43, 0x80, + 0x41, 0xfe, 0x76, 0xe8, 0x00, 0xb2, 0x72, 0xab, 0xe8, 0x3c, 0x94, 0x63, 0x15, 0x96, 0xbf, 0x7c, + 0xa2, 0x9c, 0x78, 0x77, 0x55, 0xfd, 0xfc, 0x8f, 0x7f, 0xbe, 0xee, 0xbf, 0x88, 0xf2, 0x5a, 0xc7, + 0x7f, 0x06, 0xd0, 0x97, 0x0a, 0x0c, 0xf2, 0x0c, 0x47, 0x2f, 0x9f, 0xb4, 0x13, 0x08, 0xeb, 0x29, + 0x57, 0x07, 0x75, 0x91, 0x1b, 0xbf, 0x82, 0xe6, 0xb4, 0x4e, 0xff, 0x48, 0x68, 0xfb, 0x41, 0xd0, + 0x0f, 0xb4, 0x7d, 0x51, 0xee, 0x07, 0xe8, 0x0b, 0x05, 0x86, 0x9a, 0xbb, 0x0b, 0x9a, 0xeb, 0x68, + 0xa8, 0x7d, 0x83, 0xca, 0xcf, 0xa7, 0x11, 0x95, 0xbc, 0x66, 0x38, 0xaf, 0x0b, 0xe8, 0x7c, 0x47, + 0x5e, 0xe8, 0x47, 0x05, 0xc6, 0x93, 0x96, 0x0f, 0xb4, 0xdc, 0xd1, 0x4e, 0x97, 0x7d, 0x26, 0x7f, + 0xfd, 0x29, 0xb5, 0x24, 0xd1, 0x25, 0x4e, 0xf4, 0x2a, 0x9a, 0x4f, 0x22, 0xda, 0xcc, 0x4b, 0x2d, + 0x9a, 0x8e, 0xe8, 0x97, 0x28, 0xf3, 0xc8, 0x10, 0x49, 0xc3, 0xfc, 0xf8, 0x8c, 0x4b, 0xc3, 0x3c, + 0x61, 0x52, 0xa9, 0xb7, 0x38, 0xf3, 0x1b, 0x68, 0xb9, 0x3b, 0xf3, 0xe8, 0x34, 0xd3, 0xf6, 0xe5, + 0x92, 0x73, 0x80, 0x1e, 0x2a, 0x30, 0xd9, 0x61, 0x16, 0xa2, 0x9b, 0x27, 0x13, 0x4a, 0x9c, 0xd6, + 0xf9, 0x57, 0x9f, 0x5e, 0x51, 0x3a, 0x73, 0x83, 0x3b, 0xf3, 0x0a, 0x2a, 0x76, 0x77, 0x06, 0xdb, + 0xb6, 0x11, 0x75, 0x08, 0x7d, 0xa3, 0xc0, 0x70, 0x64, 0x74, 0xa0, 0x2b, 0xdd, 0xeb, 0x26, 0x5e, + 0xe2, 0x57, 0xd3, 0x09, 0xa7, 0xc9, 0x14, 0x51, 0xe7, 0xc7, 0x6a, 0xed, 0xd7, 0x68, 0x94, 0xe3, + 0x73, 0x23, 0x4d, 0x94, 0x13, 0x87, 0x5c, 0x9a, 0x28, 0x27, 0x8f, 0x28, 0xf5, 0x3a, 0x77, 0x41, + 0x43, 0x0b, 0xdd, 0xa3, 0xdc, 0x5c, 0xd7, 0x6c, 0xc3, 0x72, 0x36, 0xe9, 0x6a, 0xe9, 0xd1, 0x61, + 0x41, 0x79, 0x7c, 0x58, 0x50, 0xfe, 0x3e, 0x2c, 0x28, 0x5f, 0x1d, 0x15, 0xfa, 0x1e, 0x1f, 0x15, + 0xfa, 0xfe, 0x3c, 0x2a, 0xf4, 0x7d, 0x70, 0x33, 0x7d, 0xef, 0xdf, 0x93, 0x66, 0xf8, 0x08, 0x28, + 0x67, 0xf9, 0xf9, 0xb5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x87, 0xf2, 0x87, 0x5d, 0x1b, 0x12, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1377,19 +1367,9 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintQuery(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - { - size, err := m.DefaultQuotingParams.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- dAtA[i] = 0x12 { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.DefaultQuotingParams.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1455,20 +1435,20 @@ func (m *QueryVaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if len(m.MostRecentClientIds) > 0 { - dAtA5 := make([]byte, len(m.MostRecentClientIds)*10) - var j4 int + dAtA4 := make([]byte, len(m.MostRecentClientIds)*10) + var j3 int for _, num := range m.MostRecentClientIds { for num >= 1<<7 { - dAtA5[j4] = uint8(uint64(num)&0x7f | 0x80) + dAtA4[j3] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j4++ + j3++ } - dAtA5[j4] = uint8(num) - j4++ + dAtA4[j3] = uint8(num) + j3++ } - i -= j4 - copy(dAtA[i:], dAtA5[:j4]) - i = encodeVarintQuery(dAtA, i, uint64(j4)) + i -= j3 + copy(dAtA[i:], dAtA4[:j3]) + i = encodeVarintQuery(dAtA, i, uint64(j3)) i-- dAtA[i] = 0x32 } @@ -2053,8 +2033,6 @@ func (m *QueryParamsResponse) Size() (n int) { } var l int _ = l - l = m.Params.Size() - n += 1 + l + sovQuery(uint64(l)) l = m.DefaultQuotingParams.Size() n += 1 + l + sovQuery(uint64(l)) l = m.OperatorParams.Size() @@ -2369,39 +2347,6 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field DefaultQuotingParams", wireType) } @@ -2434,7 +2379,7 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field OperatorParams", wireType) } From d74cc70cf5cfc23eb3d1f7cbcfa33cba359e6a2c Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 2 Oct 2024 17:33:53 -0400 Subject: [PATCH 069/120] Return undefined from getOrderbookMidPriceMap (#2441) --- indexer/services/ender/__tests__/lib/candles-generator.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index 34935d6c53..e9021cbf7b 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -471,8 +471,6 @@ describe('candleHelper', () => { expectTimingStats(); }); -<<<<<<< HEAD -======= it('Updates previous candle orderBookMidPriceClose if startTime is past candle resolution', async () => { // Create existing candles const existingPrice: string = '7000'; @@ -674,7 +672,6 @@ describe('candleHelper', () => { }); ->>>>>>> 672169be7 (Fix issue with flaky candle test (#2430)) it('successfully creates an orderbook price map for each market', async () => { await Promise.all([ OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), From c105563e5f94774a535ab19a12000fc5287ed349 Mon Sep 17 00:00:00 2001 From: shrenujb <98204323+shrenujb@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:11:03 -0400 Subject: [PATCH 070/120] [TRA-654] add listing module state init into v7 upgrade handler (#2432) Signed-off-by: Shrenuj Bansal --- protocol/app/upgrades.go | 1 + protocol/app/upgrades/v7.0.0/upgrade.go | 24 +++++++++++++ .../upgrades/v7.0.0/upgrade_container_test.go | 36 +++++++++++++++++++ protocol/x/listing/types/constants.go | 2 ++ 4 files changed, 63 insertions(+) diff --git a/protocol/app/upgrades.go b/protocol/app/upgrades.go index 3103802ac6..8c16de0aab 100644 --- a/protocol/app/upgrades.go +++ b/protocol/app/upgrades.go @@ -33,6 +33,7 @@ func (app *App) setupUpgradeHandlers() { app.AccountKeeper, app.PricesKeeper, app.VaultKeeper, + app.ListingKeeper, ), ) } diff --git a/protocol/app/upgrades/v7.0.0/upgrade.go b/protocol/app/upgrades/v7.0.0/upgrade.go index afc87cfada..e0543670b9 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade.go +++ b/protocol/app/upgrades/v7.0.0/upgrade.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" + listingtypes "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" + upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -12,6 +14,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" + listingkeeper "github.com/dydxprotocol/v4-chain/protocol/x/listing/keeper" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" @@ -194,12 +197,30 @@ func migrateVaultSharesToMegavaultShares(ctx sdk.Context, k vaultkeeper.Keeper) ctx.Logger().Info("Successfully migrated vault shares to megavault shares") } +func initListingModuleState(ctx sdk.Context, listingKeeper listingkeeper.Keeper) { + // Set hard cap on listed markets + err := listingKeeper.SetMarketsHardCap(ctx, listingtypes.DefaultMarketsHardCap) + if err != nil { + panic(fmt.Sprintf("failed to set markets hard cap: %s", err)) + } + + // Set listing vault deposit params + err = listingKeeper.SetListingVaultDepositParams( + ctx, + listingtypes.DefaultParams(), + ) + if err != nil { + panic(fmt.Sprintf("failed to set listing vault deposit params: %s", err)) + } +} + func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, accountKeeper authkeeper.AccountKeeper, pricesKeeper pricestypes.PricesKeeper, vaultKeeper vaultkeeper.Keeper, + listingKeeper listingkeeper.Keeper, ) upgradetypes.UpgradeHandler { return func(ctx context.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { sdkCtx := lib.UnwrapSDKContext(ctx, "app/upgrades") @@ -217,6 +238,9 @@ func CreateUpgradeHandler( // Migrate vault shares to megavault shares. migrateVaultSharesToMegavaultShares(sdkCtx, vaultKeeper) + // Initialize listing module state. + initListingModuleState(sdkCtx, listingKeeper) + return mm.RunMigrations(ctx, configurator, vm) } } diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go index dc8ef454ff..e2fa3ec9a3 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go @@ -6,6 +6,8 @@ import ( "math/big" "testing" + listingtypes "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" + "github.com/cosmos/gogoproto/proto" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -58,6 +60,9 @@ func postUpgradeChecks(node *containertest.Node, t *testing.T) { // Check that the affiliates module has been initialized with the default tiers. postUpgradeAffiliatesModuleTiersCheck(node, t) + + // Check that the listing module state has been initialized with the hard cap and default deposit params. + postUpgradeListingModuleStateCheck(node, t) } func postUpgradeVaultParamsCheck(node *containertest.Node, t *testing.T) { @@ -203,3 +208,34 @@ func postUpgradeMegavaultModuleAccCheck(node *containertest.Node, t *testing.T) err = proto.UnmarshalText(resp.String(), &moduleAccResp) require.NoError(t, err) } + +func postUpgradeListingModuleStateCheck(node *containertest.Node, t *testing.T) { + // Check that the listing module state has been initialized with the hard cap and default deposit params. + resp, err := containertest.Query( + node, + listingtypes.NewQueryClient, + listingtypes.QueryClient.ListingVaultDepositParams, + &listingtypes.QueryListingVaultDepositParams{}, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + listingVaultDepositParamsResp := listingtypes.QueryListingVaultDepositParamsResponse{} + err = proto.UnmarshalText(resp.String(), &listingVaultDepositParamsResp) + require.NoError(t, err) + require.Equal(t, listingtypes.DefaultParams(), listingVaultDepositParamsResp.Params) + + resp, err = containertest.Query( + node, + listingtypes.NewQueryClient, + listingtypes.QueryClient.MarketsHardCap, + &listingtypes.QueryMarketsHardCap{}, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + marketsHardCapResp := listingtypes.QueryMarketsHardCapResponse{} + err = proto.UnmarshalText(resp.String(), &marketsHardCapResp) + require.NoError(t, err) + require.Equal(t, uint32(500), marketsHardCapResp.HardCap) +} diff --git a/protocol/x/listing/types/constants.go b/protocol/x/listing/types/constants.go index b428add511..b473f78360 100644 --- a/protocol/x/listing/types/constants.go +++ b/protocol/x/listing/types/constants.go @@ -14,4 +14,6 @@ const ( DefaultQuantumConversionExponent = -9 ResolutionOffset = -6 + + DefaultMarketsHardCap = 500 ) From d0da9caa991b4480b569b67853b7eda73c41d544 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:19:35 -0400 Subject: [PATCH 071/120] [CT-1259] move account plus test functions to testutil (#2444) --- protocol/testutil/tx/msg_tx.go | 134 +++++++++++++++++- protocol/x/accountplus/ante/ante_test.go | 105 +------------- .../accountplus/ante/circuit_breaker_test.go | 5 +- .../x/accountplus/authenticator/base_test.go | 7 +- .../signature_authenticator_test.go | 102 +------------ 5 files changed, 147 insertions(+), 206 deletions(-) diff --git a/protocol/testutil/tx/msg_tx.go b/protocol/testutil/tx/msg_tx.go index 969e6a3d00..b3f645fb74 100644 --- a/protocol/testutil/tx/msg_tx.go +++ b/protocol/testutil/tx/msg_tx.go @@ -2,14 +2,142 @@ package tx import ( "fmt" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/dydxprotocol/v4-chain/protocol/app/module" + "math/rand" + "time" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/dydxprotocol/v4-chain/protocol/app/module" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) +func MakeTxBuilder( + ctx sdk.Context, + gen client.TxConfig, + msgs []sdk.Msg, + feeAmt sdk.Coins, + gas uint64, + chainID string, + accNums, accSeqs []uint64, + signers, signatures []cryptotypes.PrivKey, + selectedAuthenticators []uint64, +) (client.TxBuilder, error) { + sigs := make([]signing.SignatureV2, len(signers)) + + // create a random length memo + r := rand.New(rand.NewSource(time.Now().UnixNano())) + memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) + signMode, err := authsigning.APISignModeToInternal(gen.SignModeHandler().DefaultMode()) + if err != nil { + return nil, err + } + + // 1st round: set SignatureV2 with empty signatures, to set correct + // signer infos. + for i, p := range signers { + sigs[i] = signing.SignatureV2{ + PubKey: p.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + }, + Sequence: accSeqs[i], + } + } + + baseTxBuilder := gen.NewTxBuilder() + + txBuilder, ok := baseTxBuilder.(authtx.ExtensionOptionsTxBuilder) + if !ok { + return nil, fmt.Errorf("expected authtx.ExtensionOptionsTxBuilder, got %T", baseTxBuilder) + } + if len(selectedAuthenticators) > 0 { + value, err := codectypes.NewAnyWithValue(&types.TxExtension{ + SelectedAuthenticators: selectedAuthenticators, + }) + if err != nil { + return nil, err + } + txBuilder.SetNonCriticalExtensionOptions(value) + } + + err = txBuilder.SetMsgs(msgs...) + if err != nil { + return nil, err + } + err = txBuilder.SetSignatures(sigs...) + if err != nil { + return nil, err + } + txBuilder.SetMemo(memo) + txBuilder.SetFeeAmount(feeAmt) + txBuilder.SetGasLimit(gas) + + // 2nd round: once all signer infos are set, every signer can sign. + for i, p := range signatures { + signerData := authsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + signBytes, err := authsigning.GetSignBytesAdapter( + ctx, gen.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) + if err != nil { + panic(err) + } + + sig, err := p.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i].Data.(*signing.SingleSignatureData).Signature = sig + err = txBuilder.SetSignatures(sigs...) + if err != nil { + panic(err) + } + } + + return txBuilder, nil +} + +// GenTx generates a signed mock transaction. +func GenTx( + ctx sdk.Context, + gen client.TxConfig, + msgs []sdk.Msg, + feeAmt sdk.Coins, + gas uint64, + chainID string, + accNums, accSeqs []uint64, + signers, signatures []cryptotypes.PrivKey, + selectedAuthenticators []uint64, +) (sdk.Tx, error) { + builder, err := MakeTxBuilder( + ctx, + gen, + msgs, + feeAmt, + gas, + chainID, + accNums, + accSeqs, + signers, + signatures, + selectedAuthenticators, + ) + if err != nil { + return nil, err + } + return builder.GetTx(), nil +} + // Returns the encoded msg as transaction. Will panic if encoding fails. func MustGetTxBytes(msgs ...sdk.Msg) []byte { tx := constants.TestEncodingCfg.TxConfig.NewTxBuilder() diff --git a/protocol/x/accountplus/ante/ante_test.go b/protocol/x/accountplus/ante/ante_test.go index c6d7969f3f..8250e05f3c 100644 --- a/protocol/x/accountplus/ante/ante_test.go +++ b/protocol/x/accountplus/ante/ante_test.go @@ -6,23 +6,18 @@ import ( "math/rand" "os" "testing" - "time" storetypes "cosmossdk.io/store/types" tmtypes "github.com/cometbft/cometbft/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testtx "github.com/dydxprotocol/v4-chain/protocol/testutil/tx" "github.com/stretchr/testify/suite" @@ -31,7 +26,6 @@ import ( testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/ante" - "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) type AuthenticatorAnteSuite struct { @@ -128,7 +122,7 @@ func (s *AuthenticatorAnteSuite) TestSignatureVerificationNoAuthenticatorInStore } feeCoins := constants.TestFeeCoins_5Cents - tx, err := GenTx( + tx, err := testtx.GenTx( s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ @@ -201,7 +195,7 @@ func (s *AuthenticatorAnteSuite) TestSignatureVerificationWithAuthenticatorInSto "Expected smart account to be active", ) - tx, err := GenTx( + tx, err := testtx.GenTx( s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ @@ -268,7 +262,7 @@ func (s *AuthenticatorAnteSuite) TestFeePayerGasComsumption() { "Expected smart account to be active", ) - tx, err := GenTx( + tx, err := testtx.GenTx( s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ @@ -384,7 +378,7 @@ func (s *AuthenticatorAnteSuite) TestSpecificAuthenticator() { for name, tc := range testCases { s.Run(name, func() { - tx, err := GenTx( + tx, err := testtx.GenTx( s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ @@ -416,92 +410,3 @@ func (s *AuthenticatorAnteSuite) TestSpecificAuthenticator() { }) } } - -// GenTx generates a signed mock transaction. -func GenTx( - ctx sdk.Context, - gen client.TxConfig, - msgs []sdk.Msg, - feeAmt sdk.Coins, - gas uint64, - chainID string, - accNums, accSeqs []uint64, - signers, signatures []cryptotypes.PrivKey, - selectedAuthenticators []uint64, -) (sdk.Tx, error) { - sigs := make([]signing.SignatureV2, len(signers)) - - // create a random length memo - r := rand.New(rand.NewSource(time.Now().UnixNano())) - memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) - signMode, err := authsigning.APISignModeToInternal(gen.SignModeHandler().DefaultMode()) - if err != nil { - return nil, err - } - - // 1st round: set SignatureV2 with empty signatures, to set correct - // signer infos. - for i, p := range signers { - sigs[i] = signing.SignatureV2{ - PubKey: p.PubKey(), - Data: &signing.SingleSignatureData{ - SignMode: signMode, - }, - Sequence: accSeqs[i], - } - } - - baseTxBuilder := gen.NewTxBuilder() - - txBuilder, ok := baseTxBuilder.(authtx.ExtensionOptionsTxBuilder) - if !ok { - return nil, fmt.Errorf("expected authtx.ExtensionOptionsTxBuilder, got %T", baseTxBuilder) - } - if len(selectedAuthenticators) > 0 { - value, err := codectypes.NewAnyWithValue(&types.TxExtension{ - SelectedAuthenticators: selectedAuthenticators, - }) - if err != nil { - return nil, err - } - txBuilder.SetNonCriticalExtensionOptions(value) - } - - err = txBuilder.SetMsgs(msgs...) - if err != nil { - return nil, err - } - err = txBuilder.SetSignatures(sigs...) - if err != nil { - return nil, err - } - txBuilder.SetMemo(memo) - txBuilder.SetFeeAmount(feeAmt) - txBuilder.SetGasLimit(gas) - - // 2nd round: once all signer infos are set, every signer can sign. - for i, p := range signatures { - signerData := authsigning.SignerData{ - ChainID: chainID, - AccountNumber: accNums[i], - Sequence: accSeqs[i], - } - signBytes, err := authsigning.GetSignBytesAdapter( - ctx, gen.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) - if err != nil { - panic(err) - } - - sig, err := p.Sign(signBytes) - if err != nil { - panic(err) - } - sigs[i].Data.(*signing.SingleSignatureData).Signature = sig - err = txBuilder.SetSignatures(sigs...) - if err != nil { - panic(err) - } - } - - return txBuilder.GetTx(), nil -} diff --git a/protocol/x/accountplus/ante/circuit_breaker_test.go b/protocol/x/accountplus/ante/circuit_breaker_test.go index b774154142..3b554911c9 100644 --- a/protocol/x/accountplus/ante/circuit_breaker_test.go +++ b/protocol/x/accountplus/ante/circuit_breaker_test.go @@ -17,6 +17,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/app/config" testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + testtx "github.com/dydxprotocol/v4-chain/protocol/testutil/tx" "github.com/stretchr/testify/suite" @@ -133,7 +134,7 @@ func (s *AuthenticatorCircuitBreakerAnteSuite) TestCircuitBreakerAnte() { feeCoins := constants.TestFeeCoins_5Cents // Generate a test transaction - tx, _ := GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ + tx, _ := testtx.GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ testMsg1, testMsg2, }, feeCoins, 300000, "", []uint64{0, 0}, []uint64{0, 0}, []cryptotypes.PrivKey{ @@ -176,7 +177,7 @@ func (s *AuthenticatorCircuitBreakerAnteSuite) TestCircuitBreakerAnte() { s.Require().NoError(err) // Generate a test transaction with a selected authenticator - tx, _ = GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ + tx, _ = testtx.GenTx(s.Ctx, s.EncodingConfig.TxConfig, []sdk.Msg{ testMsg1, testMsg2, }, feeCoins, 300000, "", []uint64{0, 0}, []uint64{0, 0}, []cryptotypes.PrivKey{ diff --git a/protocol/x/accountplus/authenticator/base_test.go b/protocol/x/accountplus/authenticator/base_test.go index dbc6a89f0a..37e7b6abd1 100644 --- a/protocol/x/accountplus/authenticator/base_test.go +++ b/protocol/x/accountplus/authenticator/base_test.go @@ -17,6 +17,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/app" testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + testtx "github.com/dydxprotocol/v4-chain/protocol/testutil/tx" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" smartaccounttypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/stretchr/testify/suite" @@ -103,7 +104,7 @@ func (s *BaseAuthenticatorSuite) GenSimpleTx(msgs []sdk.Msg, signers []cryptotyp accSeqs = append(accSeqs, account.GetSequence()) } - tx, err := GenTx( + tx, err := testtx.GenTx( s.Ctx, txconfig, msgs, @@ -114,6 +115,7 @@ func (s *BaseAuthenticatorSuite) GenSimpleTx(msgs []sdk.Msg, signers []cryptotyp accSeqs, signers, signers, + nil, ) if err != nil { return nil, err @@ -139,7 +141,7 @@ func (s *BaseAuthenticatorSuite) GenSimpleTxWithSelectedAuthenticators( accSeqs = append(accSeqs, account.GetSequence()) } - baseTxBuilder, err := MakeTxBuilder( + baseTxBuilder, err := testtx.MakeTxBuilder( s.Ctx, txconfig, msgs, @@ -150,6 +152,7 @@ func (s *BaseAuthenticatorSuite) GenSimpleTxWithSelectedAuthenticators( accSeqs, signers, signers, + nil, ) if err != nil { return nil, err diff --git a/protocol/x/accountplus/authenticator/signature_authenticator_test.go b/protocol/x/accountplus/authenticator/signature_authenticator_test.go index 096bd60b45..49fafc15e9 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator_test.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator_test.go @@ -1,18 +1,13 @@ package authenticator_test import ( - "math/rand" "os" "testing" - "time" - "github.com/cosmos/cosmos-sdk/client" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testtx "github.com/dydxprotocol/v4-chain/protocol/testutil/tx" "github.com/stretchr/testify/suite" @@ -247,7 +242,7 @@ func (s *SigVerifyAuthenticationSuite) TestSignatureAuthenticator() { for _, tc := range tests { s.Run(tc.Description, func() { // Generate a transaction based on the test cases - tx, _ := GenTx( + tx, _ := testtx.GenTx( s.Ctx, s.EncodingConfig.TxConfig, tc.TestData.Msgs, @@ -258,6 +253,7 @@ func (s *SigVerifyAuthenticationSuite) TestSignatureAuthenticator() { tc.TestData.AccSeqs, tc.TestData.Signers, tc.TestData.Signatures, + nil, ) ak := s.tApp.App.AccountKeeper sigModeHandler := s.EncodingConfig.TxConfig.SignModeHandler() @@ -313,95 +309,3 @@ func (s *SigVerifyAuthenticationSuite) TestSignatureAuthenticator() { }) } } - -func MakeTxBuilder(ctx sdk.Context, - gen client.TxConfig, - msgs []sdk.Msg, - feeAmt sdk.Coins, - gas uint64, - chainID string, - accNums, - accSeqs []uint64, - signers []cryptotypes.PrivKey, - signatures []cryptotypes.PrivKey, -) (client.TxBuilder, error) { - sigs := make([]signing.SignatureV2, len(signatures)) - - // create a random length memo - r := rand.New(rand.NewSource(time.Now().UnixNano())) - memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) - signMode, err := authsigning.APISignModeToInternal(gen.SignModeHandler().DefaultMode()) - if err != nil { - return nil, err - } - - // 1st round: set SignatureV2 with empty signatures, to set correct - // signer infos. - for i, p := range signers { - sigs[i] = signing.SignatureV2{ - PubKey: p.PubKey(), - Data: &signing.SingleSignatureData{ - SignMode: signMode, - }, - Sequence: accSeqs[i], - } - } - - tx := gen.NewTxBuilder() - err = tx.SetMsgs(msgs...) - if err != nil { - return nil, err - } - err = tx.SetSignatures(sigs...) - if err != nil { - return nil, err - } - tx.SetMemo(memo) - tx.SetFeeAmount(feeAmt) - tx.SetGasLimit(gas) - - // 2nd round: once all signer infos are set, every signer can sign. - for i, p := range signatures { - signerData := authsigning.SignerData{ - ChainID: chainID, - AccountNumber: accNums[i], - Sequence: accSeqs[i], - } - signBytes, err := authsigning.GetSignBytesAdapter( - ctx, gen.SignModeHandler(), signMode, signerData, tx.GetTx()) - if err != nil { - panic(err) - } - sig, err := p.Sign(signBytes) - if err != nil { - panic(err) - } - sigs[i].Data.(*signing.SingleSignatureData).Signature = sig - } - - err = tx.SetSignatures(sigs...) - if err != nil { - panic(err) - } - return tx, nil -} - -// GenTx generates a signed mock transaction. -func GenTx( - ctx sdk.Context, - gen client.TxConfig, - msgs []sdk.Msg, - feeAmt sdk.Coins, - gas uint64, - chainID string, - accNums, - accSeqs []uint64, - signers []cryptotypes.PrivKey, - signatures []cryptotypes.PrivKey, -) (sdk.Tx, error) { - tx, err := MakeTxBuilder(ctx, gen, msgs, feeAmt, gas, chainID, accNums, accSeqs, signers, signatures) - if err != nil { - return nil, err - } - return tx.GetTx(), nil -} From e2a4c4676ff96cf515d3b3f9b2280561e8525444 Mon Sep 17 00:00:00 2001 From: Christopher-Li Date: Thu, 3 Oct 2024 13:20:27 -0400 Subject: [PATCH 072/120] Update indexer testnet url (#2312) --- indexer/pnpm-lock.yaml | 24 +-- indexer/services/comlink/package.json | 2 +- .../comlink/public/api-documentation.md | 150 +++++++++--------- 3 files changed, 84 insertions(+), 92 deletions(-) diff --git a/indexer/pnpm-lock.yaml b/indexer/pnpm-lock.yaml index 0b961578cc..98acd5cf3f 100644 --- a/indexer/pnpm-lock.yaml +++ b/indexer/pnpm-lock.yaml @@ -477,7 +477,7 @@ importers: cors: ^2.8.5 dd-trace: ^3.32.1 dotenv-flow: ^3.2.0 - dydx-widdershins: ^4.0.7 + dydx-widdershins: ^4.0.8 express: ^4.18.1 express-request-id: ^1.4.0 express-validator: ^6.14.2 @@ -516,7 +516,7 @@ importers: cors: 2.8.5 dd-trace: 3.32.1 dotenv-flow: 3.2.0 - dydx-widdershins: 4.0.7 + dydx-widdershins: 4.0.8 express: 4.18.1 express-request-id: 1.4.1 express-validator: 6.14.2 @@ -6839,7 +6839,7 @@ packages: typescript: 4.9.5 validator: 13.7.0 yamljs: 0.3.0 - yargs: 17.5.1 + yargs: 17.7.2 dev: false /@tsoa/runtime/5.0.0: @@ -8296,7 +8296,6 @@ packages: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 dev: false - optional: true /co/4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -8850,8 +8849,8 @@ packages: dev: false optional: true - /dydx-widdershins/4.0.7: - resolution: {integrity: sha512-uHC9p1fvmRuJed/lvA6C70F0IFcKdFjCt5MZKCmP79e5l51sqn4DsPp3fRY/o4zCIr3GWjhULZbF5uPPH4p+sw==} + /dydx-widdershins/4.0.8: + resolution: {integrity: sha512-fisnybZb7TpCoV80YKWi8XLykUzwCGtv9NCIizIRkacLd8KqCJjRdquR+nlaza3bSl+kJic1Suw9yfgBq3P92Q==} hasBin: true dependencies: dot: 1.1.3 @@ -13134,7 +13133,7 @@ packages: oas-kit-common: 1.0.8 reftools: 1.1.9 yaml: 1.10.2 - yargs: 17.5.1 + yargs: 17.7.2 dev: false /oas-schema-walker/1.1.5: @@ -14807,7 +14806,7 @@ packages: oas-validator: 5.0.8 reftools: 1.1.9 yaml: 1.10.2 - yargs: 17.5.1 + yargs: 17.7.2 transitivePeerDependencies: - encoding dev: false @@ -15725,15 +15724,9 @@ packages: decamelize: 1.2.0 dev: false - /yargs-parser/21.0.1: - resolution: {integrity: sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==} - engines: {node: '>=12'} - /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: false - optional: true /yargs/12.0.5: resolution: {integrity: sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==} @@ -15777,7 +15770,7 @@ packages: require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 - yargs-parser: 21.0.1 + yargs-parser: 21.1.1 /yargs/17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} @@ -15791,7 +15784,6 @@ packages: y18n: 5.0.8 yargs-parser: 21.1.1 dev: false - optional: true /yn/3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} diff --git a/indexer/services/comlink/package.json b/indexer/services/comlink/package.json index b4ac31ae38..448ac57866 100644 --- a/indexer/services/comlink/package.json +++ b/indexer/services/comlink/package.json @@ -41,7 +41,7 @@ "cors": "^2.8.5", "dd-trace": "^3.32.1", "dotenv-flow": "^3.2.0", - "dydx-widdershins": "^4.0.7", + "dydx-widdershins": "^4.0.8", "express": "^4.18.1", "express-request-id": "^1.4.0", "express-validator": "^6.14.2", diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index a7ac9f0000..8a3518a869 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -6,7 +6,7 @@ Base URLs: * For **the deployment by DYDX token holders**, use https://indexer.dydx.trade/v4 -* For **Testnet**, use https://dydx-testnet.imperator.co/v4 +* For **Testnet**, use https://indexer.v4testnet.dydx.exchange/v4 Note: Messages on Indexer WebSocket feeds are typically more recent than data fetched via Indexer's REST API, because the latter is backed by read replicas of the databases that feed the former. Ordinarily this difference is minimal (less than a second), but it might become prolonged under load. Please see [Indexer Architecture](https://dydx.exchange/blog/v4-deep-dive-indexer) for more information. @@ -28,7 +28,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/affiliates/address', params={ 'referralCode': 'string' @@ -46,7 +46,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/affiliates/address?referralCode=string`, { @@ -104,7 +104,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/addresses/{address}/subaccountNumber/{subaccountNumber}', headers = headers) @@ -120,7 +120,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/addresses/{address}/subaccountNumber/{subaccountNumber}`, { @@ -239,7 +239,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/addresses/{address}/parentSubaccountNumber/{parentSubaccountNumber}', headers = headers) @@ -255,7 +255,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/addresses/{address}/parentSubaccountNumber/{parentSubaccountNumber}`, { @@ -382,7 +382,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.post(f'{baseURL}/addresses/{address}/registerToken', headers = headers) @@ -401,7 +401,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/addresses/{address}/registerToken`, { @@ -458,7 +458,7 @@ import requests # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.post(f'{baseURL}/addresses/{address}/testNotification') @@ -470,7 +470,7 @@ print(r.json()) // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/addresses/{address}/testNotification`, { @@ -517,7 +517,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/affiliates/metadata', params={ 'address': 'string' @@ -535,7 +535,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/affiliates/metadata?address=string`, { @@ -595,7 +595,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/affiliates/snapshot', headers = headers) @@ -611,7 +611,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/affiliates/snapshot`, { @@ -688,7 +688,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/affiliates/total_volume', params={ 'address': 'string' @@ -706,7 +706,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/affiliates/total_volume?address=string`, { @@ -764,7 +764,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/assetPositions', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -782,7 +782,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/assetPositions?address=string&subaccountNumber=0.1`, { @@ -849,7 +849,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/assetPositions/parentSubaccountNumber', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -867,7 +867,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/assetPositions/parentSubaccountNumber?address=string&parentSubaccountNumber=0.1`, { @@ -934,7 +934,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/candles/perpetualMarkets/{ticker}', params={ 'resolution': '1MIN' @@ -952,7 +952,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/candles/perpetualMarkets/{ticker}?resolution=1MIN`, { @@ -1043,7 +1043,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/compliance/screen/{address}', headers = headers) @@ -1059,7 +1059,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/compliance/screen/{address}`, { @@ -1119,7 +1119,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/fills', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -1137,7 +1137,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/fills?address=string&subaccountNumber=0.1`, { @@ -1230,7 +1230,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/fills/parentSubaccount', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -1248,7 +1248,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/fills/parentSubaccount?address=string&parentSubaccountNumber=0.1`, { @@ -1341,7 +1341,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/height', headers = headers) @@ -1357,7 +1357,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/height`, { @@ -1410,7 +1410,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/historicalBlockTradingRewards/{address}', headers = headers) @@ -1426,7 +1426,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/historicalBlockTradingRewards/{address}`, { @@ -1493,7 +1493,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/historicalFunding/{ticker}', headers = headers) @@ -1509,7 +1509,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/historicalFunding/{ticker}`, { @@ -1578,7 +1578,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/historical-pnl', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -1596,7 +1596,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/historical-pnl?address=string&subaccountNumber=0.1`, { @@ -1675,7 +1675,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/historical-pnl/parentSubaccountNumber', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -1693,7 +1693,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/historical-pnl/parentSubaccountNumber?address=string&parentSubaccountNumber=0.1`, { @@ -1771,7 +1771,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/historicalTradingRewardAggregations/{address}', params={ 'period': 'DAILY' @@ -1789,7 +1789,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/historicalTradingRewardAggregations/{address}?period=DAILY`, { @@ -1868,7 +1868,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/orderbooks/perpetualMarket/{ticker}', headers = headers) @@ -1884,7 +1884,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/orderbooks/perpetualMarket/{ticker}`, { @@ -1953,7 +1953,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/orders', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -1971,7 +1971,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/orders?address=string&subaccountNumber=0.1`, { @@ -2147,7 +2147,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/orders/parentSubaccountNumber', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -2165,7 +2165,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/orders/parentSubaccountNumber?address=string&parentSubaccountNumber=0.1`, { @@ -2341,7 +2341,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/orders/{orderId}', headers = headers) @@ -2357,7 +2357,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/orders/{orderId}`, { @@ -2437,7 +2437,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/perpetualMarkets', headers = headers) @@ -2453,7 +2453,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/perpetualMarkets`, { @@ -2559,7 +2559,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/perpetualPositions', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -2577,7 +2577,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/perpetualPositions?address=string&subaccountNumber=0.1`, { @@ -2667,7 +2667,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/perpetualPositions/parentSubaccountNumber', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -2685,7 +2685,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/perpetualPositions/parentSubaccountNumber?address=string&parentSubaccountNumber=0.1`, { @@ -2775,7 +2775,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/trader/search', params={ 'searchParam': 'string' @@ -2793,7 +2793,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/trader/search?searchParam=string`, { @@ -2856,7 +2856,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/sparklines', params={ 'timePeriod': 'ONE_DAY' @@ -2874,7 +2874,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/sparklines?timePeriod=ONE_DAY`, { @@ -2944,7 +2944,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/time', headers = headers) @@ -2960,7 +2960,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/time`, { @@ -3013,7 +3013,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/trades/perpetualMarket/{ticker}', headers = headers) @@ -3029,7 +3029,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/trades/perpetualMarket/{ticker}`, { @@ -3104,7 +3104,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/transfers', params={ 'address': 'string', 'subaccountNumber': '0.1' @@ -3122,7 +3122,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/transfers?address=string&subaccountNumber=0.1`, { @@ -3206,7 +3206,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/transfers/parentSubaccountNumber', params={ 'address': 'string', 'parentSubaccountNumber': '0.1' @@ -3224,7 +3224,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/transfers/parentSubaccountNumber?address=string&parentSubaccountNumber=0.1`, { @@ -3308,7 +3308,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/transfers/between', params={ 'sourceAddress': 'string', 'sourceSubaccountNumber': '0.1', 'recipientAddress': 'string', 'recipientSubaccountNumber': '0.1' @@ -3326,7 +3326,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/transfers/between?sourceAddress=string&sourceSubaccountNumber=0.1&recipientAddress=string&recipientSubaccountNumber=0.1`, { @@ -3411,7 +3411,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/vault/v1/megavault/historicalPnl', headers = headers) @@ -3427,7 +3427,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/vault/v1/megavault/historicalPnl`, { @@ -3503,7 +3503,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/vault/v1/vaults/historicalPnl', headers = headers) @@ -3519,7 +3519,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/vault/v1/vaults/historicalPnl`, { @@ -3600,7 +3600,7 @@ headers = { # For the deployment by DYDX token holders, use # baseURL = 'https://indexer.dydx.trade/v4' -baseURL = 'https://dydx-testnet.imperator.co/v4' +baseURL = 'https://indexer.v4testnet.dydx.exchange/v4' r = requests.get(f'{baseURL}/vault/v1/megavault/positions', headers = headers) @@ -3616,7 +3616,7 @@ const headers = { // For the deployment by DYDX token holders, use // const baseURL = 'https://indexer.dydx.trade/v4'; -const baseURL = 'https://dydx-testnet.imperator.co/v4'; +const baseURL = 'https://indexer.v4testnet.dydx.exchange/v4'; fetch(`${baseURL}/vault/v1/megavault/positions`, { From b018d6f08123fe540ead34a4e93e71100a2b9493 Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Thu, 3 Oct 2024 15:10:34 -0400 Subject: [PATCH 073/120] [OTE-849] Add metrics to track revenue shares (#2449) --- protocol/lib/metrics/constants.go | 5 +++++ protocol/x/revshare/types/types.go | 15 +++++++++++++++ protocol/x/subaccounts/keeper/transfer.go | 16 +++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/protocol/lib/metrics/constants.go b/protocol/lib/metrics/constants.go index a0f851eb58..795856530f 100644 --- a/protocol/lib/metrics/constants.go +++ b/protocol/lib/metrics/constants.go @@ -305,6 +305,8 @@ const ( UpdateSubaccounts = "update_subaccounts" SubaccountOwner = "subaccount_owner" MarketMapperRevenueDistribution = "market_mapper_revenue_distribution" + RevenueShareDistribution = "revenue_share_distribution" + NetFeesPostRevenueShareDistribution = "net_fees_post_revenue_share_distribution" // Liquidation Daemon. CheckCollateralizationForSubaccounts = "check_collateralization_for_subaccounts" @@ -410,6 +412,9 @@ const ( ValidatorNumMatchedTakerOrders = "validator_num_matched_taker_orders" ValidatorVolumeQuoteQuantums = "validator_volume_quote_quantums" + // x/revshare + RevShareType = "rev_share_type" + // x/acocuntplus TimestampNonce = "timestamp_nonce" diff --git a/protocol/x/revshare/types/types.go b/protocol/x/revshare/types/types.go index 17ecd548a3..5cdbb6afda 100644 --- a/protocol/x/revshare/types/types.go +++ b/protocol/x/revshare/types/types.go @@ -60,3 +60,18 @@ type RevSharesForFill struct { FeeSourceToRevSharePpm map[RevShareFeeSource]uint32 AllRevShares []RevShare } + +func (r RevShareType) String() string { + switch r { + case REV_SHARE_TYPE_UNSPECIFIED: + return "REV_SHARE_TYPE_UNSPECIFIED" + case REV_SHARE_TYPE_MARKET_MAPPER: + return "REV_SHARE_TYPE_MARKET_MAPPER" + case REV_SHARE_TYPE_UNCONDITIONAL: + return "REV_SHARE_TYPE_UNCONDITIONAL" + case REV_SHARE_TYPE_AFFILIATE: + return "REV_SHARE_TYPE_AFFILIATE" + default: + return "UNKNOWN" + } +} diff --git a/protocol/x/subaccounts/keeper/transfer.go b/protocol/x/subaccounts/keeper/transfer.go index ecf79952be..52ffedce14 100644 --- a/protocol/x/subaccounts/keeper/transfer.go +++ b/protocol/x/subaccounts/keeper/transfer.go @@ -250,7 +250,15 @@ func (k Keeper) DistributeFees( return err } - // emit a metric for the amount of fees transferred to the market mapper + // Emit revenue share + metrics.AddSampleWithLabels( + metrics.RevenueShareDistribution, + metrics.GetMetricValueFromBigInt(revShare.QuoteQuantums), + metrics.GetLabelForStringValue(metrics.RevShareType, revShare.RevShareType.String()), + metrics.GetLabelForStringValue(metrics.RecipientAddress, revShare.Recipient), + ) + + // Old metric which is being kept for now to ensure data continuity if revShare.RevShareType == revsharetypes.REV_SHARE_TYPE_MARKET_MAPPER { labels := []metrics.Label{ metrics.GetLabelForIntValue(metrics.MarketId, int(perpetual.Params.MarketId)), @@ -289,6 +297,12 @@ func (k Keeper) DistributeFees( panic("fee collector share is < 0") } + // Emit fee colletor metric + metrics.AddSample( + metrics.NetFeesPostRevenueShareDistribution, + metrics.GetMetricValueFromBigInt(feeCollectorShare), + ) + // Transfer fees to the fee collector if err := k.TransferFees( ctx, From 6aeb05e420e8dc72346ef8f736e9abaa0adbb89e Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:58:35 -0400 Subject: [PATCH 074/120] [CT-1268] fix genesis for account plus (#2452) --- protocol/x/accountplus/genesis.go | 14 +++- protocol/x/accountplus/genesis_test.go | 74 ++++++++++++++++++- .../x/accountplus/keeper/authenticators.go | 22 ++++-- protocol/x/accountplus/keeper/keeper.go | 70 +++++++++++++++++- 4 files changed, 169 insertions(+), 11 deletions(-) diff --git a/protocol/x/accountplus/genesis.go b/protocol/x/accountplus/genesis.go index d84289a0db..66601dfbc2 100644 --- a/protocol/x/accountplus/genesis.go +++ b/protocol/x/accountplus/genesis.go @@ -18,7 +18,19 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { if err != nil { panic(err) } + + params := k.GetParams(ctx) + nextAuthenticatorId := k.InitializeOrGetNextAuthenticatorId(ctx) + + data, err := k.GetAllAuthenticatorData(ctx) + if err != nil { + panic(err) + } + return &types.GenesisState{ - Accounts: accounts, + Accounts: accounts, + Params: params, + NextAuthenticatorId: nextAuthenticatorId, + AuthenticatorData: data, } } diff --git a/protocol/x/accountplus/genesis_test.go b/protocol/x/accountplus/genesis_test.go index dc0a82d055..df323ff829 100644 --- a/protocol/x/accountplus/genesis_test.go +++ b/protocol/x/accountplus/genesis_test.go @@ -18,7 +18,10 @@ func TestImportExportGenesis(t *testing.T) { // The order of this list may not match the order in GenesisState. We want our tests to be deterministic so // order of expectedAccountStates was manually set based on test debug. This ordering should only be changed if // additional accounts added to genesisState. If a feature breaks the existing ordering, should look into why. - expectedAccountStates []types.AccountState + expectedAccountStates []types.AccountState + expectedParams types.Params + expectedNextAuthenticatorId uint64 + expectedAuthenticatorData []types.AuthenticatorData }{ "non-empty genesis": { genesisState: &types.GenesisState{ @@ -45,6 +48,32 @@ func TestImportExportGenesis(t *testing.T) { }, }, }, + Params: types.Params{ + IsSmartAccountActive: true, + }, + NextAuthenticatorId: 100, + AuthenticatorData: []types.AuthenticatorData{ + { + Address: constants.AliceAccAddress.String(), + Authenticators: []types.AccountAuthenticator{ + { + Id: 1, + Type: "MessageFilter", + Config: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + }, + }, + { + Address: constants.BobAccAddress.String(), + Authenticators: []types.AccountAuthenticator{ + { + Id: 1, + Type: "ClobPairIdFilter", + Config: []byte("0,1,2"), + }, + }, + }, + }, }, expectedAccountStates: []types.AccountState{ { @@ -69,6 +98,32 @@ func TestImportExportGenesis(t *testing.T) { }, }, }, + expectedParams: types.Params{ + IsSmartAccountActive: true, + }, + expectedNextAuthenticatorId: 100, + expectedAuthenticatorData: []types.AuthenticatorData{ + { + Address: constants.BobAccAddress.String(), + Authenticators: []types.AccountAuthenticator{ + { + Id: 1, + Type: "ClobPairIdFilter", + Config: []byte("0,1,2"), + }, + }, + }, + { + Address: constants.AliceAccAddress.String(), + Authenticators: []types.AccountAuthenticator{ + { + Id: 1, + Type: "MessageFilter", + Config: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + }, + }, + }, }, "empty genesis": { genesisState: &types.GenesisState{ @@ -95,11 +150,26 @@ func TestImportExportGenesis(t *testing.T) { "Keeper account states do not match Genesis account states", ) + // Check that keeper params are correct + actualParams := k.GetParams(ctx) + require.Equal(t, tc.expectedParams, actualParams) + + // Check that keeper next authenticator id is correct + actualNextAuthenticatorId := k.InitializeOrGetNextAuthenticatorId(ctx) + require.Equal(t, tc.expectedNextAuthenticatorId, actualNextAuthenticatorId) + + // Check that keeper authenticator data is correct + actualAuthenticatorData, _ := k.GetAllAuthenticatorData(ctx) + require.Equal(t, tc.expectedAuthenticatorData, actualAuthenticatorData) + exportedGenesis := accountplus.ExportGenesis(ctx, k) // Check that the exported state matches the expected state expectedGenesis := &types.GenesisState{ - Accounts: tc.expectedAccountStates, + Accounts: tc.expectedAccountStates, + Params: tc.expectedParams, + NextAuthenticatorId: tc.expectedNextAuthenticatorId, + AuthenticatorData: tc.expectedAuthenticatorData, } require.Equal(t, *exportedGenesis, *expectedGenesis) }) diff --git a/protocol/x/accountplus/keeper/authenticators.go b/protocol/x/accountplus/keeper/authenticators.go index 71d8b9aede..82f7289c1f 100644 --- a/protocol/x/accountplus/keeper/authenticators.go +++ b/protocol/x/accountplus/keeper/authenticators.go @@ -96,21 +96,29 @@ func (k Keeper) AddAuthenticator( } k.SetNextAuthenticatorId(ctx, id+1) - - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - []byte(types.AuthenticatorKeyPrefix), - ) authenticator := types.AccountAuthenticator{ Id: id, Type: authenticatorType, Config: config, } - b := k.cdc.MustMarshal(&authenticator) - store.Set(types.KeyAccountId(account, id), b) + k.SetAuthenticator(ctx, account.String(), id, authenticator) return id, nil } +func (k Keeper) SetAuthenticator( + ctx sdk.Context, + account string, + authenticatorId uint64, + authenticator types.AccountAuthenticator, +) { + store := prefix.NewStore( + ctx.KVStore(k.storeKey), + []byte(types.AuthenticatorKeyPrefix), + ) + b := k.cdc.MustMarshal(&authenticator) + store.Set(types.BuildKey(account, authenticatorId), b) +} + // RemoveAuthenticator removes an authenticator from an account func (k Keeper) RemoveAuthenticator(ctx sdk.Context, account sdk.AccAddress, authenticatorId uint64) error { store := prefix.NewStore( diff --git a/protocol/x/accountplus/keeper/keeper.go b/protocol/x/accountplus/keeper/keeper.go index def0ced51e..d63297e19f 100644 --- a/protocol/x/accountplus/keeper/keeper.go +++ b/protocol/x/accountplus/keeper/keeper.go @@ -1,8 +1,10 @@ package keeper import ( + "bytes" "errors" "fmt" + "strings" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" @@ -53,7 +55,14 @@ func (k Keeper) GetAllAccountStates(ctx sdk.Context) ([]types.AccountState, erro accounts := []types.AccountState{} for ; iterator.Valid(); iterator.Next() { - accountState, found := k.GetAccountState(ctx, iterator.Key()) + key := iterator.Key() + + // Temporary workaround to exclude smart account kv pairs. + if bytes.HasPrefix(key, []byte(types.SmartAccountKeyPrefix)) { + continue + } + + accountState, found := k.GetAccountState(ctx, key) if !found { return accounts, errors.New("Could not get account state for address: " + sdk.AccAddress(iterator.Key()).String()) } @@ -73,9 +82,68 @@ func (k Keeper) SetGenesisState(ctx sdk.Context, data types.GenesisState) error k.SetAccountState(ctx, address, account) } + k.SetParams(ctx, data.Params) + k.SetNextAuthenticatorId(ctx, data.NextAuthenticatorId) + + for _, data := range data.GetAuthenticatorData() { + address := data.GetAddress() + for _, authenticator := range data.GetAuthenticators() { + k.SetAuthenticator(ctx, address, authenticator.Id, authenticator) + } + } + return nil } +// GetAllAuthenticatorData is used in genesis export to export all the authenticator for all accounts +func (k Keeper) GetAllAuthenticatorData(ctx sdk.Context) ([]types.AuthenticatorData, error) { + var accountAuthenticators []types.AuthenticatorData + + parse := func(key []byte, value []byte) error { + var authenticator types.AccountAuthenticator + err := k.cdc.Unmarshal(value, &authenticator) + if err != nil { + return err + } + + // Key is of format `SA/A/{accountAddr}/{authenticatorId}`. + // Extract account address from key. + accountAddr := strings.Split(string(key), "/")[2] + + // Check if this entry is for a new address or the same as the last one processed + if len(accountAuthenticators) == 0 || + accountAuthenticators[len(accountAuthenticators)-1].Address != accountAddr { + // If it's a new address, create a new AuthenticatorData entry + accountAuthenticators = append(accountAuthenticators, types.AuthenticatorData{ + Address: accountAddr, + Authenticators: []types.AccountAuthenticator{authenticator}, + }) + } else { + // If it's the same address, append the authenticator to the last entry in the list + lastIndex := len(accountAuthenticators) - 1 + accountAuthenticators[lastIndex].Authenticators = append( + accountAuthenticators[lastIndex].Authenticators, + authenticator, + ) + } + + return nil + } + + // Iterate over all entries in the store using a prefix iterator + iterator := storetypes.KVStorePrefixIterator(ctx.KVStore(k.storeKey), []byte(types.AuthenticatorKeyPrefix)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + err := parse(iterator.Key(), iterator.Value()) + if err != nil { + return nil, err + } + } + + return accountAuthenticators, nil +} + func GetAccountPlusStateWithTimestampNonceDetails( address sdk.AccAddress, tsNonce uint64, From b8e03ea60c145e9ee61b468d90e1c92db2bf5af6 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:20:53 -0400 Subject: [PATCH 075/120] [TRA-671] Prevent connect messages in x/authz (#2434) --- protocol/lib/ante/nested_msg.go | 9 +++++++ protocol/lib/ante/nested_msg_test.go | 35 +++++++++++++++++++++++++++ protocol/testutil/msgs/nested_msgs.go | 10 ++++++++ 3 files changed, 54 insertions(+) diff --git a/protocol/lib/ante/nested_msg.go b/protocol/lib/ante/nested_msg.go index db2a09ec77..cf3cd6433f 100644 --- a/protocol/lib/ante/nested_msg.go +++ b/protocol/lib/ante/nested_msg.go @@ -12,6 +12,7 @@ import ( ) const DYDX_MSG_PREFIX = "/" + constants.AppName +const CONNECT_MSG_PREFIX = "/connect" // IsNestedMsg returns true if the given msg is a nested msg. func IsNestedMsg(msg sdk.Msg) bool { @@ -32,6 +33,11 @@ func IsDydxMsg(msg sdk.Msg) bool { return strings.HasPrefix(sdk.MsgTypeURL(msg), DYDX_MSG_PREFIX) } +// IsConnectMsg returns true if the given msg is a Connect custom msg. +func IsConnectMsg(msg sdk.Msg) bool { + return strings.HasPrefix(sdk.MsgTypeURL(msg), CONNECT_MSG_PREFIX) +} + // ValidateNestedMsg returns err if the given msg is an invalid nested msg. func ValidateNestedMsg(msg sdk.Msg) error { if !IsNestedMsg(msg) { @@ -80,6 +86,9 @@ func validateInnerMsg(msg sdk.Msg) error { if IsDydxMsg(inner) { return fmt.Errorf("Invalid nested msg for MsgExec: dydx msg type") } + if IsConnectMsg(inner) { + return fmt.Errorf("Invalid nested msg for MsgExec: Connect msg type") + } } // For "internal msgs", we allow them, because they are designed to be nested. diff --git a/protocol/lib/ante/nested_msg_test.go b/protocol/lib/ante/nested_msg_test.go index 94ffe95c58..0a98a94b84 100644 --- a/protocol/lib/ante/nested_msg_test.go +++ b/protocol/lib/ante/nested_msg_test.go @@ -22,6 +22,7 @@ var ( invalidInnerMsgErr_AppInjected = fmt.Errorf("Invalid nested msg: app-injected msg type") invalidInnerMsgErr_Nested = fmt.Errorf("Invalid nested msg: double-nested msg type") invalidInnerMsgErr_Dydx = fmt.Errorf("Invalid nested msg for MsgExec: dydx msg type") + invalidInnerMsgErr_Connect = fmt.Errorf("Invalid nested msg for MsgExec: Connect msg type") ) func TestIsNestedMsg_Empty(t *testing.T) { @@ -106,6 +107,36 @@ func TestIsDydxMsg_Valid(t *testing.T) { } } +func TestIsConnectMsg_Invalid(t *testing.T) { + allConnectMsgs := lib.MergeAllMapsMustHaveDistinctKeys( + appmsgs.NormalMsgsConnect, + ) + allMsgsMinusConnect := lib.MergeAllMapsMustHaveDistinctKeys(appmsgs.AllowMsgs, appmsgs.DisallowMsgs) + for key := range allConnectMsgs { + delete(allMsgsMinusConnect, key) + } + allNonNilSampleMsgs := testmsgs.GetNonNilSampleMsgs(allMsgsMinusConnect) + + for _, sampleMsg := range allNonNilSampleMsgs { + t.Run(sampleMsg.Name, func(t *testing.T) { + require.False(t, ante.IsConnectMsg(sampleMsg.Msg)) + }) + } +} + +func TestIsConnectMsg_Valid(t *testing.T) { + allConnectMsgs := lib.MergeAllMapsMustHaveDistinctKeys( + appmsgs.NormalMsgsConnect, + ) + allNonNilSampleMsgs := testmsgs.GetNonNilSampleMsgs(allConnectMsgs) + + for _, sampleMsg := range allNonNilSampleMsgs { + t.Run(sampleMsg.Name, func(t *testing.T) { + require.True(t, ante.IsConnectMsg(sampleMsg.Msg)) + }) + } +} + func TestValidateNestedMsg(t *testing.T) { tests := map[string]struct { msg sdk.Msg @@ -143,6 +174,10 @@ func TestValidateNestedMsg(t *testing.T) { msg: &testmsgs.MsgExecWithDydxMessage, expectedErr: invalidInnerMsgErr_Dydx, }, + "Invalid MsgExec: Connect custom msg": { + msg: &testmsgs.MsgExecWithConnectMessage, + expectedErr: invalidInnerMsgErr_Connect, + }, "Valid: empty inner msg": { msg: testmsgs.MsgSubmitProposalWithEmptyInner, expectedErr: nil, diff --git a/protocol/testutil/msgs/nested_msgs.go b/protocol/testutil/msgs/nested_msgs.go index 7b4b91625f..207903bd27 100644 --- a/protocol/testutil/msgs/nested_msgs.go +++ b/protocol/testutil/msgs/nested_msgs.go @@ -10,6 +10,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/encoding" prices "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" sending "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" + marketmap "github.com/skip-mev/connect/v2/x/marketmap/types" ) func init() { @@ -46,6 +47,9 @@ func init() { _ = testTxBuilder.SetMsgs(&MsgExecWithDydxMessage) MsgExecWithDydxMessageTxBytes, _ = testEncodingCfg.TxConfig.TxEncoder()(testTxBuilder.GetTx()) + _ = testTxBuilder.SetMsgs(&MsgExecWithConnectMessage) + MsgExecWithConnectMessageTxBytes, _ = testEncodingCfg.TxConfig.TxEncoder()(testTxBuilder.GetTx()) + _ = testTxBuilder.SetMsgs(MsgSubmitProposalWithUpgrade) MsgSubmitProposalWithUpgradeTxBytes, _ = testEncodingCfg.TxConfig.TxEncoder()(testTxBuilder.GetTx()) @@ -120,6 +124,12 @@ var ( ) MsgExecWithDydxMessageTxBytes []byte + MsgExecWithConnectMessage = authz.NewMsgExec( + constants.AliceAccAddress, + []sdk.Msg{&marketmap.MsgUpsertMarkets{}}, + ) + MsgExecWithConnectMessageTxBytes []byte + // Valid MsgSubmitProposals MsgSubmitProposalWithUpgrade, _ = gov.NewMsgSubmitProposal( []sdk.Msg{MsgSoftwareUpgrade}, nil, testProposer, testMetadata, testTitle, testSummary, false) From 595160d657b6eacce709fb0247fe9738b98524ac Mon Sep 17 00:00:00 2001 From: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:28:33 -0400 Subject: [PATCH 076/120] fix tsnonce preventing multisignature bug (#2453) --- protocol/x/accountplus/ante/timestampnonce.go | 11 ++++++++--- protocol/x/accountplus/ante/timestampnonce_test.go | 7 ++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/protocol/x/accountplus/ante/timestampnonce.go b/protocol/x/accountplus/ante/timestampnonce.go index a914a6cc83..4871766e76 100644 --- a/protocol/x/accountplus/ante/timestampnonce.go +++ b/protocol/x/accountplus/ante/timestampnonce.go @@ -20,9 +20,14 @@ func IsTimestampNonceTx(ctx sdk.Context, tx sdk.Tx) (bool, error) { return false, err } - if len(signatures) != 1 { - return false, errorsmod.Wrap(sdkerrors.ErrTxDecode, "more than one signature") + // multi signature cannot contain timestamp nonce + if len(signatures) > 1 { + for _, sig := range signatures { + if accountpluskeeper.IsTimestampNonce(sig.Sequence) { + return false, errorsmod.Wrap(sdkerrors.ErrTxDecode, "multi signature contains timestampnonce") + } + } } - return accountpluskeeper.IsTimestampNonce(signatures[0].Sequence), nil + return len(signatures) == 1 && accountpluskeeper.IsTimestampNonce(signatures[0].Sequence), nil } diff --git a/protocol/x/accountplus/ante/timestampnonce_test.go b/protocol/x/accountplus/ante/timestampnonce_test.go index 88ba421526..1a5fc5cc3a 100644 --- a/protocol/x/accountplus/ante/timestampnonce_test.go +++ b/protocol/x/accountplus/ante/timestampnonce_test.go @@ -32,7 +32,12 @@ func TestIsTimestampNonceTx(t *testing.T) { expectedResult: true, expectedErr: false, }, - "Returns error for more than one signature": { + "Returns false with no error if multisignature with regular seq number": { + seqs: []uint64{1, 1}, + expectedResult: false, + expectedErr: false, + }, + "Returns error for multisignature with timestamp nonce": { seqs: []uint64{keeper.TimestampNonceSequenceCutoff, keeper.TimestampNonceSequenceCutoff}, expectedResult: false, expectedErr: true, From 000f6015bd6db5e2e24d83ebc8a8f100af2934f7 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Thu, 3 Oct 2024 16:28:48 -0400 Subject: [PATCH 077/120] feat: make PML compatible with OE by staging in-memory CLOB side effects (#2447) --- .../src/codegen/dydxprotocol/bundle.ts | 516 +++++++++--------- .../dydxprotocol/clob/finalize_block.ts | 66 +++ .../v4-protos/src/codegen/gogoproto/bundle.ts | 4 +- .../v4-protos/src/codegen/google/bundle.ts | 22 +- proto/dydxprotocol/clob/finalize_block.proto | 16 + protocol/mocks/MemClob.go | 17 +- protocol/testutil/keeper/clob.go | 4 +- protocol/x/clob/abci.go | 6 + protocol/x/clob/abci_test.go | 6 +- protocol/x/clob/genesis.go | 2 +- protocol/x/clob/keeper/clob_pair.go | 174 ++++-- protocol/x/clob/keeper/clob_pair_test.go | 32 +- protocol/x/clob/keeper/deleveraging_test.go | 4 +- .../x/clob/keeper/get_price_premium_test.go | 2 +- protocol/x/clob/keeper/keeper.go | 54 +- protocol/x/clob/keeper/liquidations_test.go | 22 +- protocol/x/clob/keeper/mev_test.go | 4 +- .../keeper/msg_server_place_order_test.go | 4 +- protocol/x/clob/keeper/orders_test.go | 18 +- .../x/clob/keeper/process_operations_test.go | 2 +- protocol/x/clob/memclob/memclob.go | 5 +- .../memclob_get_impact_price_subticks_test.go | 2 +- protocol/x/clob/types/finalize_block.pb.go | 390 +++++++++++++ protocol/x/clob/types/keys.go | 6 + protocol/x/clob/types/memclob.go | 2 +- protocol/x/listing/keeper/listing.go | 35 +- protocol/x/listing/keeper/listing_test.go | 19 +- protocol/x/listing/types/expected_keepers.go | 3 +- 28 files changed, 1024 insertions(+), 413 deletions(-) create mode 100644 indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/finalize_block.ts create mode 100644 proto/dydxprotocol/clob/finalize_block.proto create mode 100644 protocol/x/clob/types/finalize_block.pb.go diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts index 3324f5cd90..3550eca53c 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts @@ -26,161 +26,162 @@ import * as _29 from "./bridge/tx"; import * as _30 from "./clob/block_rate_limit_config"; import * as _31 from "./clob/clob_pair"; import * as _32 from "./clob/equity_tier_limit_config"; -import * as _33 from "./clob/genesis"; -import * as _34 from "./clob/liquidations_config"; -import * as _35 from "./clob/liquidations"; -import * as _36 from "./clob/matches"; -import * as _37 from "./clob/mev"; -import * as _38 from "./clob/operation"; -import * as _39 from "./clob/order_removals"; -import * as _40 from "./clob/order"; -import * as _41 from "./clob/process_proposer_matches_events"; -import * as _42 from "./clob/query"; -import * as _43 from "./clob/streaming"; -import * as _44 from "./clob/tx"; -import * as _45 from "./daemons/bridge/bridge"; -import * as _46 from "./daemons/liquidation/liquidation"; -import * as _47 from "./daemons/pricefeed/price_feed"; -import * as _48 from "./delaymsg/block_message_ids"; -import * as _49 from "./delaymsg/delayed_message"; -import * as _50 from "./delaymsg/genesis"; -import * as _51 from "./delaymsg/query"; -import * as _52 from "./delaymsg/tx"; -import * as _53 from "./epochs/epoch_info"; -import * as _54 from "./epochs/genesis"; -import * as _55 from "./epochs/query"; -import * as _56 from "./feetiers/genesis"; -import * as _57 from "./feetiers/params"; -import * as _58 from "./feetiers/query"; -import * as _59 from "./feetiers/tx"; -import * as _60 from "./govplus/genesis"; -import * as _61 from "./govplus/query"; -import * as _62 from "./govplus/tx"; -import * as _63 from "./indexer/events/events"; -import * as _64 from "./indexer/indexer_manager/event"; -import * as _65 from "./indexer/off_chain_updates/off_chain_updates"; -import * as _66 from "./indexer/protocol/v1/clob"; -import * as _67 from "./indexer/protocol/v1/perpetual"; -import * as _68 from "./indexer/protocol/v1/subaccount"; -import * as _69 from "./indexer/protocol/v1/vault"; -import * as _70 from "./indexer/redis/redis_order"; -import * as _71 from "./indexer/shared/removal_reason"; -import * as _72 from "./indexer/socks/messages"; -import * as _73 from "./listing/genesis"; -import * as _74 from "./listing/params"; -import * as _75 from "./listing/query"; -import * as _76 from "./listing/tx"; -import * as _77 from "./perpetuals/genesis"; -import * as _78 from "./perpetuals/params"; -import * as _79 from "./perpetuals/perpetual"; -import * as _80 from "./perpetuals/query"; -import * as _81 from "./perpetuals/tx"; -import * as _82 from "./prices/genesis"; -import * as _83 from "./prices/market_param"; -import * as _84 from "./prices/market_price"; -import * as _85 from "./prices/query"; -import * as _86 from "./prices/tx"; -import * as _87 from "./ratelimit/capacity"; -import * as _88 from "./ratelimit/genesis"; -import * as _89 from "./ratelimit/limit_params"; -import * as _90 from "./ratelimit/pending_send_packet"; -import * as _91 from "./ratelimit/query"; -import * as _92 from "./ratelimit/tx"; -import * as _93 from "./revshare/genesis"; -import * as _94 from "./revshare/params"; -import * as _95 from "./revshare/query"; -import * as _96 from "./revshare/revshare"; -import * as _97 from "./revshare/tx"; -import * as _98 from "./rewards/genesis"; -import * as _99 from "./rewards/params"; -import * as _100 from "./rewards/query"; -import * as _101 from "./rewards/reward_share"; -import * as _102 from "./rewards/tx"; -import * as _103 from "./sending/genesis"; -import * as _104 from "./sending/query"; -import * as _105 from "./sending/transfer"; -import * as _106 from "./sending/tx"; -import * as _107 from "./stats/genesis"; -import * as _108 from "./stats/params"; -import * as _109 from "./stats/query"; -import * as _110 from "./stats/stats"; -import * as _111 from "./stats/tx"; -import * as _112 from "./subaccounts/asset_position"; -import * as _113 from "./subaccounts/genesis"; -import * as _114 from "./subaccounts/perpetual_position"; -import * as _115 from "./subaccounts/query"; -import * as _116 from "./subaccounts/streaming"; -import * as _117 from "./subaccounts/subaccount"; -import * as _118 from "./vault/genesis"; -import * as _119 from "./vault/params"; -import * as _120 from "./vault/query"; -import * as _121 from "./vault/share"; -import * as _122 from "./vault/tx"; -import * as _123 from "./vault/vault"; -import * as _124 from "./vest/genesis"; -import * as _125 from "./vest/query"; -import * as _126 from "./vest/tx"; -import * as _127 from "./vest/vest_entry"; -import * as _135 from "./accountplus/query.lcd"; -import * as _136 from "./assets/query.lcd"; -import * as _137 from "./blocktime/query.lcd"; -import * as _138 from "./bridge/query.lcd"; -import * as _139 from "./clob/query.lcd"; -import * as _140 from "./delaymsg/query.lcd"; -import * as _141 from "./epochs/query.lcd"; -import * as _142 from "./feetiers/query.lcd"; -import * as _143 from "./listing/query.lcd"; -import * as _144 from "./perpetuals/query.lcd"; -import * as _145 from "./prices/query.lcd"; -import * as _146 from "./ratelimit/query.lcd"; -import * as _147 from "./revshare/query.lcd"; -import * as _148 from "./rewards/query.lcd"; -import * as _149 from "./stats/query.lcd"; -import * as _150 from "./subaccounts/query.lcd"; -import * as _151 from "./vault/query.lcd"; -import * as _152 from "./vest/query.lcd"; -import * as _153 from "./accountplus/query.rpc.Query"; -import * as _154 from "./affiliates/query.rpc.Query"; -import * as _155 from "./assets/query.rpc.Query"; -import * as _156 from "./blocktime/query.rpc.Query"; -import * as _157 from "./bridge/query.rpc.Query"; -import * as _158 from "./clob/query.rpc.Query"; -import * as _159 from "./delaymsg/query.rpc.Query"; -import * as _160 from "./epochs/query.rpc.Query"; -import * as _161 from "./feetiers/query.rpc.Query"; -import * as _162 from "./govplus/query.rpc.Query"; -import * as _163 from "./listing/query.rpc.Query"; -import * as _164 from "./perpetuals/query.rpc.Query"; -import * as _165 from "./prices/query.rpc.Query"; -import * as _166 from "./ratelimit/query.rpc.Query"; -import * as _167 from "./revshare/query.rpc.Query"; -import * as _168 from "./rewards/query.rpc.Query"; -import * as _169 from "./sending/query.rpc.Query"; -import * as _170 from "./stats/query.rpc.Query"; -import * as _171 from "./subaccounts/query.rpc.Query"; -import * as _172 from "./vault/query.rpc.Query"; -import * as _173 from "./vest/query.rpc.Query"; -import * as _174 from "./accountplus/tx.rpc.msg"; -import * as _175 from "./affiliates/tx.rpc.msg"; -import * as _176 from "./blocktime/tx.rpc.msg"; -import * as _177 from "./bridge/tx.rpc.msg"; -import * as _178 from "./clob/tx.rpc.msg"; -import * as _179 from "./delaymsg/tx.rpc.msg"; -import * as _180 from "./feetiers/tx.rpc.msg"; -import * as _181 from "./govplus/tx.rpc.msg"; -import * as _182 from "./listing/tx.rpc.msg"; -import * as _183 from "./perpetuals/tx.rpc.msg"; -import * as _184 from "./prices/tx.rpc.msg"; -import * as _185 from "./ratelimit/tx.rpc.msg"; -import * as _186 from "./revshare/tx.rpc.msg"; -import * as _187 from "./rewards/tx.rpc.msg"; -import * as _188 from "./sending/tx.rpc.msg"; -import * as _189 from "./stats/tx.rpc.msg"; -import * as _190 from "./vault/tx.rpc.msg"; -import * as _191 from "./vest/tx.rpc.msg"; -import * as _192 from "./lcd"; -import * as _193 from "./rpc.query"; -import * as _194 from "./rpc.tx"; +import * as _33 from "./clob/finalize_block"; +import * as _34 from "./clob/genesis"; +import * as _35 from "./clob/liquidations_config"; +import * as _36 from "./clob/liquidations"; +import * as _37 from "./clob/matches"; +import * as _38 from "./clob/mev"; +import * as _39 from "./clob/operation"; +import * as _40 from "./clob/order_removals"; +import * as _41 from "./clob/order"; +import * as _42 from "./clob/process_proposer_matches_events"; +import * as _43 from "./clob/query"; +import * as _44 from "./clob/streaming"; +import * as _45 from "./clob/tx"; +import * as _46 from "./daemons/bridge/bridge"; +import * as _47 from "./daemons/liquidation/liquidation"; +import * as _48 from "./daemons/pricefeed/price_feed"; +import * as _49 from "./delaymsg/block_message_ids"; +import * as _50 from "./delaymsg/delayed_message"; +import * as _51 from "./delaymsg/genesis"; +import * as _52 from "./delaymsg/query"; +import * as _53 from "./delaymsg/tx"; +import * as _54 from "./epochs/epoch_info"; +import * as _55 from "./epochs/genesis"; +import * as _56 from "./epochs/query"; +import * as _57 from "./feetiers/genesis"; +import * as _58 from "./feetiers/params"; +import * as _59 from "./feetiers/query"; +import * as _60 from "./feetiers/tx"; +import * as _61 from "./govplus/genesis"; +import * as _62 from "./govplus/query"; +import * as _63 from "./govplus/tx"; +import * as _64 from "./indexer/events/events"; +import * as _65 from "./indexer/indexer_manager/event"; +import * as _66 from "./indexer/off_chain_updates/off_chain_updates"; +import * as _67 from "./indexer/protocol/v1/clob"; +import * as _68 from "./indexer/protocol/v1/perpetual"; +import * as _69 from "./indexer/protocol/v1/subaccount"; +import * as _70 from "./indexer/protocol/v1/vault"; +import * as _71 from "./indexer/redis/redis_order"; +import * as _72 from "./indexer/shared/removal_reason"; +import * as _73 from "./indexer/socks/messages"; +import * as _74 from "./listing/genesis"; +import * as _75 from "./listing/params"; +import * as _76 from "./listing/query"; +import * as _77 from "./listing/tx"; +import * as _78 from "./perpetuals/genesis"; +import * as _79 from "./perpetuals/params"; +import * as _80 from "./perpetuals/perpetual"; +import * as _81 from "./perpetuals/query"; +import * as _82 from "./perpetuals/tx"; +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 "./assets/query.lcd"; +import * as _138 from "./blocktime/query.lcd"; +import * as _139 from "./bridge/query.lcd"; +import * as _140 from "./clob/query.lcd"; +import * as _141 from "./delaymsg/query.lcd"; +import * as _142 from "./epochs/query.lcd"; +import * as _143 from "./feetiers/query.lcd"; +import * as _144 from "./listing/query.lcd"; +import * as _145 from "./perpetuals/query.lcd"; +import * as _146 from "./prices/query.lcd"; +import * as _147 from "./ratelimit/query.lcd"; +import * as _148 from "./revshare/query.lcd"; +import * as _149 from "./rewards/query.lcd"; +import * as _150 from "./stats/query.lcd"; +import * as _151 from "./subaccounts/query.lcd"; +import * as _152 from "./vault/query.lcd"; +import * as _153 from "./vest/query.lcd"; +import * as _154 from "./accountplus/query.rpc.Query"; +import * as _155 from "./affiliates/query.rpc.Query"; +import * as _156 from "./assets/query.rpc.Query"; +import * as _157 from "./blocktime/query.rpc.Query"; +import * as _158 from "./bridge/query.rpc.Query"; +import * as _159 from "./clob/query.rpc.Query"; +import * as _160 from "./delaymsg/query.rpc.Query"; +import * as _161 from "./epochs/query.rpc.Query"; +import * as _162 from "./feetiers/query.rpc.Query"; +import * as _163 from "./govplus/query.rpc.Query"; +import * as _164 from "./listing/query.rpc.Query"; +import * as _165 from "./perpetuals/query.rpc.Query"; +import * as _166 from "./prices/query.rpc.Query"; +import * as _167 from "./ratelimit/query.rpc.Query"; +import * as _168 from "./revshare/query.rpc.Query"; +import * as _169 from "./rewards/query.rpc.Query"; +import * as _170 from "./sending/query.rpc.Query"; +import * as _171 from "./stats/query.rpc.Query"; +import * as _172 from "./subaccounts/query.rpc.Query"; +import * as _173 from "./vault/query.rpc.Query"; +import * as _174 from "./vest/query.rpc.Query"; +import * as _175 from "./accountplus/tx.rpc.msg"; +import * as _176 from "./affiliates/tx.rpc.msg"; +import * as _177 from "./blocktime/tx.rpc.msg"; +import * as _178 from "./bridge/tx.rpc.msg"; +import * as _179 from "./clob/tx.rpc.msg"; +import * as _180 from "./delaymsg/tx.rpc.msg"; +import * as _181 from "./feetiers/tx.rpc.msg"; +import * as _182 from "./govplus/tx.rpc.msg"; +import * as _183 from "./listing/tx.rpc.msg"; +import * as _184 from "./perpetuals/tx.rpc.msg"; +import * as _185 from "./prices/tx.rpc.msg"; +import * as _186 from "./ratelimit/tx.rpc.msg"; +import * as _187 from "./revshare/tx.rpc.msg"; +import * as _188 from "./rewards/tx.rpc.msg"; +import * as _189 from "./sending/tx.rpc.msg"; +import * as _190 from "./stats/tx.rpc.msg"; +import * as _191 from "./vault/tx.rpc.msg"; +import * as _192 from "./vest/tx.rpc.msg"; +import * as _193 from "./lcd"; +import * as _194 from "./rpc.query"; +import * as _195 from "./rpc.tx"; export namespace dydxprotocol { export const accountplus = { ..._5, ..._6, @@ -188,32 +189,32 @@ export namespace dydxprotocol { ..._8, ..._9, ..._10, - ..._135, - ..._153, - ..._174 + ..._136, + ..._154, + ..._175 }; export const affiliates = { ..._11, ..._12, ..._13, ..._14, - ..._154, - ..._175 + ..._155, + ..._176 }; export const assets = { ..._15, ..._16, ..._17, ..._18, - ..._136, - ..._155 + ..._137, + ..._156 }; export const blocktime = { ..._19, ..._20, ..._21, ..._22, ..._23, - ..._137, - ..._156, - ..._176 + ..._138, + ..._157, + ..._177 }; export const bridge = { ..._24, ..._25, @@ -221,9 +222,9 @@ export namespace dydxprotocol { ..._27, ..._28, ..._29, - ..._138, - ..._157, - ..._177 + ..._139, + ..._158, + ..._178 }; export const clob = { ..._30, ..._31, @@ -240,167 +241,168 @@ export namespace dydxprotocol { ..._42, ..._43, ..._44, - ..._139, - ..._158, - ..._178 + ..._45, + ..._140, + ..._159, + ..._179 }; export namespace daemons { - export const bridge = { ..._45 + export const bridge = { ..._46 }; - export const liquidation = { ..._46 + export const liquidation = { ..._47 }; - export const pricefeed = { ..._47 + export const pricefeed = { ..._48 }; } - export const delaymsg = { ..._48, - ..._49, + export const delaymsg = { ..._49, ..._50, ..._51, ..._52, - ..._140, - ..._159, - ..._179 + ..._53, + ..._141, + ..._160, + ..._180 }; - export const epochs = { ..._53, - ..._54, + export const epochs = { ..._54, ..._55, - ..._141, - ..._160 + ..._56, + ..._142, + ..._161 }; - export const feetiers = { ..._56, - ..._57, + export const feetiers = { ..._57, ..._58, ..._59, - ..._142, - ..._161, - ..._180 - }; - export const govplus = { ..._60, - ..._61, - ..._62, + ..._60, + ..._143, ..._162, ..._181 }; + export const govplus = { ..._61, + ..._62, + ..._63, + ..._163, + ..._182 + }; export namespace indexer { - export const events = { ..._63 + export const events = { ..._64 }; - export const indexer_manager = { ..._64 + export const indexer_manager = { ..._65 }; - export const off_chain_updates = { ..._65 + export const off_chain_updates = { ..._66 }; export namespace protocol { - export const v1 = { ..._66, - ..._67, + export const v1 = { ..._67, ..._68, - ..._69 + ..._69, + ..._70 }; } - export const redis = { ..._70 + export const redis = { ..._71 }; - export const shared = { ..._71 + export const shared = { ..._72 }; - export const socks = { ..._72 + export const socks = { ..._73 }; } - export const listing = { ..._73, - ..._74, + export const listing = { ..._74, ..._75, ..._76, - ..._143, - ..._163, - ..._182 + ..._77, + ..._144, + ..._164, + ..._183 }; - export const perpetuals = { ..._77, - ..._78, + export const perpetuals = { ..._78, ..._79, ..._80, ..._81, - ..._144, - ..._164, - ..._183 + ..._82, + ..._145, + ..._165, + ..._184 }; - export const prices = { ..._82, - ..._83, + export const prices = { ..._83, ..._84, ..._85, ..._86, - ..._145, - ..._165, - ..._184 + ..._87, + ..._146, + ..._166, + ..._185 }; - export const ratelimit = { ..._87, - ..._88, + export const ratelimit = { ..._88, ..._89, ..._90, ..._91, ..._92, - ..._146, - ..._166, - ..._185 + ..._93, + ..._147, + ..._167, + ..._186 }; - export const revshare = { ..._93, - ..._94, + export const revshare = { ..._94, ..._95, ..._96, ..._97, - ..._147, - ..._167, - ..._186 + ..._98, + ..._148, + ..._168, + ..._187 }; - export const rewards = { ..._98, - ..._99, + export const rewards = { ..._99, ..._100, ..._101, ..._102, - ..._148, - ..._168, - ..._187 + ..._103, + ..._149, + ..._169, + ..._188 }; - export const sending = { ..._103, - ..._104, + export const sending = { ..._104, ..._105, ..._106, - ..._169, - ..._188 + ..._107, + ..._170, + ..._189 }; - export const stats = { ..._107, - ..._108, + export const stats = { ..._108, ..._109, ..._110, ..._111, - ..._149, - ..._170, - ..._189 + ..._112, + ..._150, + ..._171, + ..._190 }; - export const subaccounts = { ..._112, - ..._113, + export const subaccounts = { ..._113, ..._114, ..._115, ..._116, ..._117, - ..._150, - ..._171 + ..._118, + ..._151, + ..._172 }; - export const vault = { ..._118, - ..._119, + export const vault = { ..._119, ..._120, ..._121, ..._122, ..._123, - ..._151, - ..._172, - ..._190 - }; - export const vest = { ..._124, - ..._125, - ..._126, - ..._127, + ..._124, ..._152, ..._173, ..._191 }; - export const ClientFactory = { ..._192, - ..._193, - ..._194 + export const vest = { ..._125, + ..._126, + ..._127, + ..._128, + ..._153, + ..._174, + ..._192 + }; + export const ClientFactory = { ..._193, + ..._194, + ..._195 }; } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/finalize_block.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/finalize_block.ts new file mode 100644 index 0000000000..ac6382d2c9 --- /dev/null +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/finalize_block.ts @@ -0,0 +1,66 @@ +import { ClobPair, ClobPairSDKType } from "./clob_pair"; +import * as _m0 from "protobufjs/minimal"; +import { DeepPartial } from "../../helpers"; +/** + * ClobStagedFinalizeBlockEvent defines a CLOB event staged during + * FinalizeBlock. + */ + +export interface ClobStagedFinalizeBlockEvent { + /** create_clob_pair indicates a new CLOB pair creation. */ + createClobPair?: ClobPair; +} +/** + * ClobStagedFinalizeBlockEvent defines a CLOB event staged during + * FinalizeBlock. + */ + +export interface ClobStagedFinalizeBlockEventSDKType { + /** create_clob_pair indicates a new CLOB pair creation. */ + create_clob_pair?: ClobPairSDKType; +} + +function createBaseClobStagedFinalizeBlockEvent(): ClobStagedFinalizeBlockEvent { + return { + createClobPair: undefined + }; +} + +export const ClobStagedFinalizeBlockEvent = { + encode(message: ClobStagedFinalizeBlockEvent, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.createClobPair !== undefined) { + ClobPair.encode(message.createClobPair, writer.uint32(10).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ClobStagedFinalizeBlockEvent { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseClobStagedFinalizeBlockEvent(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.createClobPair = ClobPair.decode(reader, reader.uint32()); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): ClobStagedFinalizeBlockEvent { + const message = createBaseClobStagedFinalizeBlockEvent(); + message.createClobPair = object.createClobPair !== undefined && object.createClobPair !== null ? ClobPair.fromPartial(object.createClobPair) : undefined; + 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 00375897ff..675007986c 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 _128 from "./gogo"; -export const gogoproto = { ..._128 +import * as _129 from "./gogo"; +export const gogoproto = { ..._129 }; \ 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 b2f572879c..4617ba1a6e 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 _129 from "./api/annotations"; -import * as _130 from "./api/http"; -import * as _131 from "./protobuf/descriptor"; -import * as _132 from "./protobuf/duration"; -import * as _133 from "./protobuf/timestamp"; -import * as _134 from "./protobuf/any"; +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"; export namespace google { - export const api = { ..._129, - ..._130 + export const api = { ..._130, + ..._131 }; - export const protobuf = { ..._131, - ..._132, + export const protobuf = { ..._132, ..._133, - ..._134 + ..._134, + ..._135 }; } \ No newline at end of file diff --git a/proto/dydxprotocol/clob/finalize_block.proto b/proto/dydxprotocol/clob/finalize_block.proto new file mode 100644 index 0000000000..635e59e5c4 --- /dev/null +++ b/proto/dydxprotocol/clob/finalize_block.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package dydxprotocol.clob; + +import "dydxprotocol/clob/clob_pair.proto"; + +option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"; + +// ClobStagedFinalizeBlockEvent defines a CLOB event staged during +// FinalizeBlock. +message ClobStagedFinalizeBlockEvent { + // event is the staged event. + oneof event { + // create_clob_pair indicates a new CLOB pair creation. + ClobPair create_clob_pair = 1; + } +} diff --git a/protocol/mocks/MemClob.go b/protocol/mocks/MemClob.go index abccc20590..9db224e05b 100644 --- a/protocol/mocks/MemClob.go +++ b/protocol/mocks/MemClob.go @@ -443,8 +443,21 @@ func (_m *MemClob) InsertZeroFillDeleveragingIntoOperationsQueue(subaccountId su } // MaybeCreateOrderbook provides a mock function with given fields: clobPair -func (_m *MemClob) MaybeCreateOrderbook(clobPair clobtypes.ClobPair) { - _m.Called(clobPair) +func (_m *MemClob) MaybeCreateOrderbook(clobPair clobtypes.ClobPair) bool { + ret := _m.Called(clobPair) + + if len(ret) == 0 { + panic("no return value specified for MaybeCreateOrderbook") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(clobtypes.ClobPair) bool); ok { + r0 = rf(clobPair) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 } // PlaceOrder provides a mock function with given fields: ctx, order diff --git a/protocol/testutil/keeper/clob.go b/protocol/testutil/keeper/clob.go index a7bdd239fa..9f5e6fa7e9 100644 --- a/protocol/testutil/keeper/clob.go +++ b/protocol/testutil/keeper/clob.go @@ -293,7 +293,7 @@ func CreateTestClobPairs( clobPairs []types.ClobPair, ) { for _, clobPair := range clobPairs { - _, err := clobKeeper.CreatePerpetualClobPair( + _, err := clobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobPair.MustGetPerpetualId(), @@ -352,7 +352,7 @@ func CreateNClobPair( ), ).Return() - _, err := keeper.CreatePerpetualClobPair( + _, err := keeper.CreatePerpetualClobPairAndMemStructs( ctx, items[i].Id, clobtest.MustPerpetualId(items[i]), diff --git a/protocol/x/clob/abci.go b/protocol/x/clob/abci.go index 9fd5f4a0b5..11ac034253 100644 --- a/protocol/x/clob/abci.go +++ b/protocol/x/clob/abci.go @@ -51,6 +51,12 @@ func Precommit( ctx sdk.Context, keeper keeper.Keeper, ) { + // Process all staged finalize block events, and apply necessary side effects + // (e.g. MemClob orderbook creation) that could not be done during FinalizeBlock. + // Note: this must be done in `Precommit` which is prior to `PrepareCheckState`, when + // MemClob could access the new orderbooks. + keeper.ProcessStagedFinalizeBlockEvents(ctx) + if streamingManager := keeper.GetFullNodeStreamingManager(); !streamingManager.Enabled() { return } diff --git a/protocol/x/clob/abci_test.go b/protocol/x/clob/abci_test.go index 992eb84f37..2fdbf5e8e4 100644 --- a/protocol/x/clob/abci_test.go +++ b/protocol/x/clob/abci_test.go @@ -530,7 +530,7 @@ func TestEndBlocker_Success(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -563,7 +563,7 @@ func TestEndBlocker_Success(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Eth.Id, clobtest.MustPerpetualId(constants.ClobPair_Eth), @@ -1170,7 +1170,7 @@ func TestPrepareCheckState(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobs { - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), diff --git a/protocol/x/clob/genesis.go b/protocol/x/clob/genesis.go index 3880475451..e0fac3d766 100644 --- a/protocol/x/clob/genesis.go +++ b/protocol/x/clob/genesis.go @@ -19,7 +19,7 @@ func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) if err != nil { panic(errorsmod.Wrap(types.ErrInvalidClobPairParameter, err.Error())) } - _, err = k.CreatePerpetualClobPair( + _, err = k.CreatePerpetualClobPairAndMemStructs( ctx, elem.Id, perpetualId, diff --git a/protocol/x/clob/keeper/clob_pair.go b/protocol/x/clob/keeper/clob_pair.go index 3b49d7c246..cc1cd449d6 100644 --- a/protocol/x/clob/keeper/clob_pair.go +++ b/protocol/x/clob/keeper/clob_pair.go @@ -15,6 +15,7 @@ import ( indexerevents "github.com/dydxprotocol/v4-chain/protocol/indexer/events" "github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager" "github.com/dydxprotocol/v4-chain/protocol/lib" + dydxlog "github.com/dydxprotocol/v4-chain/protocol/lib/log" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) @@ -33,6 +34,39 @@ func clobPairKey( return lib.Uint32ToKey(id.ToUint32()) } +// (Same behavior as old `CreatePerpetualClobPair`) creates the +// objects in state and in-memory. +// This function should ONLY be used to initialize genesis state +// or test setups. +// Regular CLOB logic should use `CreatePerpetualClobPair` instead. +func (k Keeper) CreatePerpetualClobPairAndMemStructs( + ctx sdk.Context, + clobPairId uint32, + perpetualId uint32, + stepSizeBaseQuantums satypes.BaseQuantums, + quantumConversionExponent int32, + subticksPerTick uint32, + status types.ClobPair_Status, +) (types.ClobPair, error) { + clobPair, err := k.createPerpetualClobPair( + ctx, + clobPairId, + perpetualId, + stepSizeBaseQuantums, + quantumConversionExponent, + subticksPerTick, + status, + ) + if err != nil { + return types.ClobPair{}, err + } + + k.MemClob.CreateOrderbook(clobPair) + k.SetClobPairIdForPerpetual(clobPair) + + return clobPair, nil +} + // CreatePerpetualClobPair creates a new perpetual CLOB pair in the store. // Additionally, it creates an order book matching the ID of the newly created CLOB pair. // @@ -49,6 +83,38 @@ func (k Keeper) CreatePerpetualClobPair( quantumConversionExponent int32, subticksPerTick uint32, status types.ClobPair_Status, +) (types.ClobPair, error) { + clobPair, err := k.createPerpetualClobPair( + ctx, + clobPairId, + perpetualId, + stepSizeBaseQuantums, + quantumConversionExponent, + subticksPerTick, + status, + ) + if err != nil { + return types.ClobPair{}, err + } + + // Don't stage events for the genesis block. + if lib.IsDeliverTxMode(ctx) { + if err := k.StageNewClobPairSideEffects(ctx, clobPair); err != nil { + return clobPair, err + } + } + + return clobPair, nil +} + +func (k Keeper) createPerpetualClobPair( + ctx sdk.Context, + clobPairId uint32, + perpetualId uint32, + stepSizeBaseQuantums satypes.BaseQuantums, + quantumConversionExponent int32, + subticksPerTick uint32, + status types.ClobPair_Status, ) (types.ClobPair, error) { clobPair := types.ClobPair{ Metadata: &types.ClobPair_PerpetualClobMetadata{ @@ -69,11 +135,36 @@ func (k Keeper) CreatePerpetualClobPair( // Write the `ClobPair` to state. k.SetClobPair(ctx, clobPair) - err := k.CreateClobPairStructures(ctx, clobPair) + perpetualId, err := clobPair.GetPerpetualId() if err != nil { - return clobPair, err + panic(err) + } + perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId) + if err != nil { + return types.ClobPair{}, err } + k.GetIndexerEventManager().AddTxnEvent( + ctx, + indexerevents.SubtypePerpetualMarket, + indexerevents.PerpetualMarketEventVersion, + indexer_manager.GetBytes( + indexerevents.NewPerpetualMarketCreateEvent( + perpetualId, + clobPair.Id, + perpetual.Params.Ticker, + perpetual.Params.MarketId, + clobPair.Status, + clobPair.QuantumConversionExponent, + perpetual.Params.AtomicResolution, + clobPair.SubticksPerTick, + clobPair.StepBaseQuantums, + perpetual.Params.LiquidityTier, + perpetual.Params.MarketType, + ), + ), + ) + return clobPair, nil } @@ -153,57 +244,36 @@ func (k Keeper) validateClobPair(ctx sdk.Context, clobPair *types.ClobPair) erro return nil } -// maybeCreateOrderbook creates a new orderbook in the memclob. -func (k Keeper) maybeCreateOrderbook(ctx sdk.Context, clobPair types.ClobPair) { - // Create the corresponding orderbook in the memclob. - k.MemClob.MaybeCreateOrderbook(clobPair) -} - -// createOrderbook creates a new orderbook in the memclob. -func (k Keeper) createOrderbook(ctx sdk.Context, clobPair types.ClobPair) { - // Create the corresponding orderbook in the memclob. - k.MemClob.CreateOrderbook(clobPair) +func (k Keeper) ApplySideEffectsForNewClobPair( + ctx sdk.Context, + clobPair types.ClobPair, +) { + if created := k.MemClob.MaybeCreateOrderbook(clobPair); !created { + dydxlog.ErrorLog( + ctx, + "ApplySideEffectsForNewClobPair: Orderbook already exists for CLOB pair", + "clob_pair", clobPair, + ) + return + } + k.SetClobPairIdForPerpetual(clobPair) } -// CreateClobPair performs all non stateful operations to create a CLOB pair. -// These include creating the corresponding orderbook in the memclob, the mapping between -// the CLOB pair and the perpetual and the indexer event. -// This function returns an error if a value for the ClobPair's id already exists in state. -func (k Keeper) CreateClobPairStructures(ctx sdk.Context, clobPair types.ClobPair) error { - // Create the corresponding orderbook in the memclob. - k.createOrderbook(ctx, clobPair) - - // Create the mapping between clob pair and perpetual. - k.SetClobPairIdForPerpetual(ctx, clobPair) - - perpetualId, err := clobPair.GetPerpetualId() - if err != nil { - panic(err) - } - perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId) - if err != nil { - return err - } +// StageNewClobPairSideEffects stages a ClobPair creation event, so that any in-memory side effects +// can happen later when the transaction and block is committed. +// Note the staged event will be processed only if below are both true: +// - The current transaction is committed. +// - The current block is agreed upon and committed by consensus. +func (k Keeper) StageNewClobPairSideEffects(ctx sdk.Context, clobPair types.ClobPair) error { + lib.AssertDeliverTxMode(ctx) - k.GetIndexerEventManager().AddTxnEvent( + k.finalizeBlockEventStager.StageFinalizeBlockEvent( ctx, - indexerevents.SubtypePerpetualMarket, - indexerevents.PerpetualMarketEventVersion, - indexer_manager.GetBytes( - indexerevents.NewPerpetualMarketCreateEvent( - perpetualId, - clobPair.Id, - perpetual.Params.Ticker, - perpetual.Params.MarketId, - clobPair.Status, - clobPair.QuantumConversionExponent, - perpetual.Params.AtomicResolution, - clobPair.SubticksPerTick, - clobPair.StepBaseQuantums, - perpetual.Params.LiquidityTier, - perpetual.Params.MarketType, - ), - ), + &types.ClobStagedFinalizeBlockEvent{ + Event: &types.ClobStagedFinalizeBlockEvent_CreateClobPair{ + CreateClobPair: &clobPair, + }, + }, ) return nil @@ -221,8 +291,7 @@ func (k Keeper) InitMemClobOrderbooks(ctx sdk.Context) { clobPairs := k.GetAllClobPairs(ctx) for _, clobPair := range clobPairs { // Create the corresponding orderbook in the memclob. - k.maybeCreateOrderbook( - ctx, + k.MemClob.MaybeCreateOrderbook( clobPair, ) } @@ -234,14 +303,13 @@ func (k Keeper) HydrateClobPairAndPerpetualMapping(ctx sdk.Context) { for _, clobPair := range clobPairs { // Create the corresponding mapping between clob pair and perpetual. k.SetClobPairIdForPerpetual( - ctx, clobPair, ) } } // SetClobPairIdForPerpetual sets the mapping between clob pair and perpetual. -func (k Keeper) SetClobPairIdForPerpetual(ctx sdk.Context, clobPair types.ClobPair) { +func (k Keeper) SetClobPairIdForPerpetual(clobPair types.ClobPair) { // If this `ClobPair` is for a perpetual, add the `clobPairId` to the list of CLOB pair IDs // that facilitate trading of this perpetual. if perpetualClobMetadata := clobPair.GetPerpetualClobMetadata(); perpetualClobMetadata != nil { diff --git a/protocol/x/clob/keeper/clob_pair_test.go b/protocol/x/clob/keeper/clob_pair_test.go index 76a56e0794..cff3f32be5 100644 --- a/protocol/x/clob/keeper/clob_pair_test.go +++ b/protocol/x/clob/keeper/clob_pair_test.go @@ -35,7 +35,7 @@ import ( // Prevent strconv unused error var _ = strconv.IntSize -func TestCreatePerpetualClobPair_MultiplePerpetual(t *testing.T) { +func TestCreatePerpetualClobPairAndMemStructs_MultiplePerpetual(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) mockIndexerEventManager := &mocks.IndexerEventManager{} ks := keepertest.NewClobKeepersTestContext(t, memClob, &mocks.BankKeeper{}, mockIndexerEventManager) @@ -71,7 +71,7 @@ func TestCreatePerpetualClobPair_MultiplePerpetual(t *testing.T) { ), ).Once().Return() //nolint: errcheck - ks.ClobKeeper.CreatePerpetualClobPair( + ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -92,7 +92,7 @@ func TestCreatePerpetualClobPair_MultiplePerpetual(t *testing.T) { ) } -func TestCreatePerpetualClobPair_FailsWithPerpetualAssociatedWithExistingClobPair(t *testing.T) { +func TestCreatePerpetualClobPairAndMemStructs_FailsWithPerpetualAssociatedWithExistingClobPair(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) // Set up mock indexer event manager that accepts anything. mockIndexerEventManager := &mocks.IndexerEventManager{} @@ -130,7 +130,7 @@ func TestCreatePerpetualClobPair_FailsWithPerpetualAssociatedWithExistingClobPai // Create test clob pair id 1, associated with perpetual id 0. newClobPair := clobtest.GenerateClobPair(clobtest.WithId(1), clobtest.WithPerpetualId(0)) - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, newClobPair.Id, newClobPair.MustGetPerpetualId(), @@ -146,7 +146,7 @@ func TestCreatePerpetualClobPair_FailsWithPerpetualAssociatedWithExistingClobPai ) } -func TestCreatePerpetualClobPair_FailsWithDuplicateClobPairId(t *testing.T) { +func TestCreatePerpetualClobPairAndMemStructs_FailsWithDuplicateClobPairId(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) mockIndexerEventManager := &mocks.IndexerEventManager{} ks := keepertest.NewClobKeepersTestContext( @@ -194,7 +194,7 @@ func TestCreatePerpetualClobPair_FailsWithDuplicateClobPairId(t *testing.T) { ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -211,7 +211,7 @@ func TestCreatePerpetualClobPair_FailsWithDuplicateClobPairId(t *testing.T) { ) } -func TestCreatePerpetualClobPair(t *testing.T) { +func TestCreatePerpetualClobPairAndMemStructs(t *testing.T) { tests := map[string]struct { // CLOB pair. clobPair types.ClobPair @@ -289,7 +289,7 @@ func TestCreatePerpetualClobPair(t *testing.T) { } // Perform the method under test. - createdClobPair, actualErr := ks.ClobKeeper.CreatePerpetualClobPair( + createdClobPair, actualErr := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, tc.clobPair.Id, clobtest.MustPerpetualId(tc.clobPair), @@ -442,7 +442,7 @@ func TestCreateMultipleClobPairs(t *testing.T) { ).Return() } - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, make.clobPair.Id, clobtest.MustPerpetualId(make.clobPair), @@ -635,7 +635,7 @@ func TestUpdateClobPair_FinalSettlement(t *testing.T) { ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -744,7 +744,7 @@ func TestUpdateClobPair(t *testing.T) { ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -802,7 +802,7 @@ func TestUpdateClobPair(t *testing.T) { ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -840,7 +840,7 @@ func TestUpdateClobPair(t *testing.T) { ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -923,7 +923,7 @@ func TestGetAllClobPairs_Sorted(t *testing.T) { ).Return().Times(len(clobPairs)) for _, clobPair := range clobPairs { - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -1048,7 +1048,7 @@ func TestIsPerpetualClobPairActive(t *testing.T) { perpetuals.InitGenesis(ks.Ctx, *ks.PerpetualsKeeper, constants.Perpetuals_DefaultGenesisState) if tc.clobPair != nil { - // allows us to circumvent CreatePerpetualClobPair and write unsupported statuses to state to + // allows us to circumvent CreatePerpetualClobPairAndMemStructs and write unsupported statuses to state to // test this function with unsupported statuses. cdc := codec.NewProtoCodec(module.InterfaceRegistry) store := prefix.NewStore(ks.Ctx.KVStore(ks.StoreKey), []byte(types.ClobPairKeyPrefix)) @@ -1183,7 +1183,7 @@ func TestAcquireNextClobPairID(t *testing.T) { clobtest.WithPerpetualId(perp.Params.Id), ) - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, perp.GetId(), diff --git a/protocol/x/clob/keeper/deleveraging_test.go b/protocol/x/clob/keeper/deleveraging_test.go index 6b0084e064..d3e6cb1ff0 100644 --- a/protocol/x/clob/keeper/deleveraging_test.go +++ b/protocol/x/clob/keeper/deleveraging_test.go @@ -419,7 +419,7 @@ func TestCanDeleverageSubaccount(t *testing.T) { ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobPair.MustGetPerpetualId(), @@ -816,7 +816,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) { ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobPair.MustGetPerpetualId(), diff --git a/protocol/x/clob/keeper/get_price_premium_test.go b/protocol/x/clob/keeper/get_price_premium_test.go index a54f805054..f75e1c8c15 100644 --- a/protocol/x/clob/keeper/get_price_premium_test.go +++ b/protocol/x/clob/keeper/get_price_premium_test.go @@ -188,7 +188,7 @@ func TestGetPricePremiumForPerpetual(t *testing.T) { ), ), ).Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, tc.args.clobPair.Id, clobtest.MustPerpetualId(tc.args.clobPair), diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index dbdfdbc0c2..633a0725b9 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -5,6 +5,7 @@ import ( "fmt" "sync/atomic" + "github.com/dydxprotocol/v4-chain/protocol/finalizeblock" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "cosmossdk.io/log" @@ -15,6 +16,7 @@ import ( liquidationtypes "github.com/dydxprotocol/v4-chain/protocol/daemons/server/types/liquidations" "github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager" "github.com/dydxprotocol/v4-chain/protocol/lib" + dydxlog "github.com/dydxprotocol/v4-chain/protocol/lib/log" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" streamingtypes "github.com/dydxprotocol/v4-chain/protocol/streaming/types" flags "github.com/dydxprotocol/v4-chain/protocol/x/clob/flags" @@ -46,8 +48,9 @@ type ( revshareKeeper types.RevShareKeeper accountPlusKeeper types.AccountPlusKeeper - indexerEventManager indexer_manager.IndexerEventManager - streamingManager streamingtypes.FullNodeStreamingManager + indexerEventManager indexer_manager.IndexerEventManager + streamingManager streamingtypes.FullNodeStreamingManager + finalizeBlockEventStager finalizeblock.EventStager[*types.ClobStagedFinalizeBlockEvent] initialized *atomic.Bool memStoreInitialized *atomic.Bool @@ -76,7 +79,7 @@ func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, memKey storetypes.StoreKey, - liquidationsStoreKey storetypes.StoreKey, + transientStoreKey storetypes.StoreKey, authorities []string, memClob types.MemClob, subaccountsKeeper types.SubaccountsKeeper, @@ -102,7 +105,7 @@ func NewKeeper( cdc: cdc, storeKey: storeKey, memKey: memKey, - transientStoreKey: liquidationsStoreKey, + transientStoreKey: transientStoreKey, authorities: lib.UniqueSliceToSet(authorities), MemClob: memClob, PerpetualIdToClobPairId: make(map[uint32][]types.ClobPairId), @@ -131,6 +134,12 @@ func NewKeeper( placeCancelOrderRateLimiter: placeCancelOrderRateLimiter, DaemonLiquidationInfo: daemonLiquidationInfo, revshareKeeper: revshareKeeper, + finalizeBlockEventStager: finalizeblock.NewEventStager[*types.ClobStagedFinalizeBlockEvent]( + transientStoreKey, + cdc, + types.StagedEventsCountKey, + types.StagedEventsKeyPrefix, + ), } // Provide the keeper to the MemClob. @@ -199,6 +208,43 @@ func (k Keeper) Initialize(ctx sdk.Context) { k.HydrateClobPairAndPerpetualMapping(checkCtx) } +func (k Keeper) GetStagedClobFinalizeBlockEvents(ctx sdk.Context) []*types.ClobStagedFinalizeBlockEvent { + return k.finalizeBlockEventStager.GetStagedFinalizeBlockEvents( + ctx, + func() *types.ClobStagedFinalizeBlockEvent { + return &types.ClobStagedFinalizeBlockEvent{} + }, + ) +} + +func (k Keeper) ProcessStagedFinalizeBlockEvents(ctx sdk.Context) { + stagedEvents := k.GetStagedClobFinalizeBlockEvents(ctx) + for _, stagedEvent := range stagedEvents { + if stagedEvent == nil { + // We don't ever expect this. However, should not panic since we are in Precommit. + dydxlog.ErrorLog( + ctx, + "got nil ClobStagedFinalizeBlockEvent, skipping", + "staged_events", + stagedEvents, + ) + continue + } + + switch event := stagedEvent.Event.(type) { + case *types.ClobStagedFinalizeBlockEvent_CreateClobPair: + k.ApplySideEffectsForNewClobPair(ctx, *event.CreateClobPair) + default: + dydxlog.ErrorLog( + ctx, + "got unknown ClobStagedFinalizeBlockEvent", + "event", + event, + ) + } + } +} + // InitMemStore initializes the memstore of the `clob` keeper. // This is called during app initialization in `app.go`, before any ABCI calls are received. func (k Keeper) InitMemStore(ctx sdk.Context) { diff --git a/protocol/x/clob/keeper/liquidations_test.go b/protocol/x/clob/keeper/liquidations_test.go index cd8ffe61fe..2b21a21281 100644 --- a/protocol/x/clob/keeper/liquidations_test.go +++ b/protocol/x/clob/keeper/liquidations_test.go @@ -332,7 +332,7 @@ func TestPlacePerpetualLiquidation(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobs { - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -447,7 +447,7 @@ func TestPlacePerpetualLiquidation_validateLiquidationAgainstClobPairStatus(t *t } clobPair := constants.ClobPair_Btc - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -1253,7 +1253,7 @@ func TestPlacePerpetualLiquidation_PreexistingLiquidation(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -1283,7 +1283,7 @@ func TestPlacePerpetualLiquidation_PreexistingLiquidation(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Eth.Id, clobtest.MustPerpetualId(constants.ClobPair_Eth), @@ -2193,7 +2193,7 @@ func TestPlacePerpetualLiquidation_Deleveraging(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -2313,7 +2313,7 @@ func TestPlacePerpetualLiquidation_SendOffchainMessages(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -3852,7 +3852,7 @@ func TestGetLiquidationInsuranceFundDelta(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -4600,7 +4600,7 @@ func TestGetPerpetualPositionToLiquidate(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -4836,7 +4836,7 @@ func TestMaybeGetLiquidationOrder(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobs { - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -5181,7 +5181,7 @@ func TestGetMaxAndMinPositionNotionalLiquidatable(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -5336,7 +5336,7 @@ func TestSortLiquidationOrders(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), diff --git a/protocol/x/clob/keeper/mev_test.go b/protocol/x/clob/keeper/mev_test.go index 6f0cd44d16..97921ebc53 100644 --- a/protocol/x/clob/keeper/mev_test.go +++ b/protocol/x/clob/keeper/mev_test.go @@ -904,7 +904,7 @@ func TestRecordMevMetrics(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobPairs { - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -1289,7 +1289,7 @@ func TestGetMidPrices(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobPairs { - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), diff --git a/protocol/x/clob/keeper/msg_server_place_order_test.go b/protocol/x/clob/keeper/msg_server_place_order_test.go index 5754c06b07..f7f0785c41 100644 --- a/protocol/x/clob/keeper/msg_server_place_order_test.go +++ b/protocol/x/clob/keeper/msg_server_place_order_test.go @@ -186,7 +186,7 @@ func TestPlaceOrder_Error(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -337,7 +337,7 @@ func TestPlaceOrder_Success(t *testing.T) { ), ), ).Once().Return() - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), diff --git a/protocol/x/clob/keeper/orders_test.go b/protocol/x/clob/keeper/orders_test.go index e8a68b6828..9c31b2bdb6 100644 --- a/protocol/x/clob/keeper/orders_test.go +++ b/protocol/x/clob/keeper/orders_test.go @@ -590,7 +590,7 @@ func TestPlaceShortTermOrder(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobs { - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), @@ -851,7 +851,7 @@ func TestAddPreexistingStatefulOrder(t *testing.T) { // Create all CLOBs. for _, clobPair := range tc.clobs { - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobPair.GetPerpetualClobMetadata().PerpetualId, @@ -982,7 +982,7 @@ func TestPlaceOrder_SendOffchainMessages(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -1039,7 +1039,7 @@ func TestPerformStatefulOrderValidation_PreExistingStatefulOrder(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -1796,7 +1796,7 @@ func TestGetStatePosition_Success(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, cp.Id, perpetualId, @@ -1853,7 +1853,7 @@ func TestGetStatePosition_PanicsOnInvalidClob(t *testing.T) { // // Create CLOB pair. // clobPair := constants.ClobPair_Asset -// clobKeeper.CreatePerpetualClobPair( +// clobKeeper.CreatePerpetualClobPairAndMemStructs( // ctx, // clobPair.Metadata.(*types.ClobPair_PerpetualClobMetadata), // satypes.BaseQuantums(clobPair.StepBaseQuantums), @@ -2014,7 +2014,7 @@ func TestInitStatefulOrders(t *testing.T) { ), ), ).Once().Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ks.Ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -2184,7 +2184,7 @@ func TestPlaceStatefulOrdersFromLastBlock(t *testing.T) { // Create CLOB pair. memClob.On("CreateOrderbook", constants.ClobPair_Btc).Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), @@ -2314,7 +2314,7 @@ func TestPlaceConditionalOrdersTriggeredInLastBlock(t *testing.T) { // Create CLOB pair. memClob.On("CreateOrderbook", constants.ClobPair_Btc).Return() - _, err := ks.ClobKeeper.CreatePerpetualClobPair( + _, err := ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, constants.ClobPair_Btc.Id, clobtest.MustPerpetualId(constants.ClobPair_Btc), diff --git a/protocol/x/clob/keeper/process_operations_test.go b/protocol/x/clob/keeper/process_operations_test.go index 178c737dd6..7ea9f4cca4 100644 --- a/protocol/x/clob/keeper/process_operations_test.go +++ b/protocol/x/clob/keeper/process_operations_test.go @@ -2461,7 +2461,7 @@ func setupProcessProposerOperationsTestCase( ).Once().Return() } - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), diff --git a/protocol/x/clob/memclob/memclob.go b/protocol/x/clob/memclob/memclob.go index d0de165e08..1229e8d3ec 100644 --- a/protocol/x/clob/memclob/memclob.go +++ b/protocol/x/clob/memclob/memclob.go @@ -158,11 +158,12 @@ func (m *MemClobPriceTimePriority) CancelOrder( // MaybeCreateOrderbook is used for updating memclob internal data structures to mark an orderbook as created. func (m *MemClobPriceTimePriority) MaybeCreateOrderbook( clobPair types.ClobPair, -) { +) (created bool) { if _, exists := m.orderbooks[clobPair.GetClobPairId()]; exists { - return + return false } m.CreateOrderbook(clobPair) + return true } // CreateOrderbook is used for updating memclob internal data structures to mark an orderbook as created. diff --git a/protocol/x/clob/memclob/memclob_get_impact_price_subticks_test.go b/protocol/x/clob/memclob/memclob_get_impact_price_subticks_test.go index 413c6fcbcb..d59d7c1f60 100644 --- a/protocol/x/clob/memclob/memclob_get_impact_price_subticks_test.go +++ b/protocol/x/clob/memclob/memclob_get_impact_price_subticks_test.go @@ -338,7 +338,7 @@ func initializeMemclobForTest( } // Create CLOB - _, err = ks.ClobKeeper.CreatePerpetualClobPair( + _, err = ks.ClobKeeper.CreatePerpetualClobPairAndMemStructs( ctx, clobPair.Id, clobtest.MustPerpetualId(clobPair), diff --git a/protocol/x/clob/types/finalize_block.pb.go b/protocol/x/clob/types/finalize_block.pb.go new file mode 100644 index 0000000000..11610e4a25 --- /dev/null +++ b/protocol/x/clob/types/finalize_block.pb.go @@ -0,0 +1,390 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dydxprotocol/clob/finalize_block.proto + +package types + +import ( + fmt "fmt" + 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 + +// ClobStagedFinalizeBlockEvent defines a CLOB event staged during +// FinalizeBlock. +type ClobStagedFinalizeBlockEvent struct { + // event is the staged event. + // + // Types that are valid to be assigned to Event: + // *ClobStagedFinalizeBlockEvent_CreateClobPair + Event isClobStagedFinalizeBlockEvent_Event `protobuf_oneof:"event"` +} + +func (m *ClobStagedFinalizeBlockEvent) Reset() { *m = ClobStagedFinalizeBlockEvent{} } +func (m *ClobStagedFinalizeBlockEvent) String() string { return proto.CompactTextString(m) } +func (*ClobStagedFinalizeBlockEvent) ProtoMessage() {} +func (*ClobStagedFinalizeBlockEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_ce1d49660993e938, []int{0} +} +func (m *ClobStagedFinalizeBlockEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ClobStagedFinalizeBlockEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ClobStagedFinalizeBlockEvent.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 *ClobStagedFinalizeBlockEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClobStagedFinalizeBlockEvent.Merge(m, src) +} +func (m *ClobStagedFinalizeBlockEvent) XXX_Size() int { + return m.Size() +} +func (m *ClobStagedFinalizeBlockEvent) XXX_DiscardUnknown() { + xxx_messageInfo_ClobStagedFinalizeBlockEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_ClobStagedFinalizeBlockEvent proto.InternalMessageInfo + +type isClobStagedFinalizeBlockEvent_Event interface { + isClobStagedFinalizeBlockEvent_Event() + MarshalTo([]byte) (int, error) + Size() int +} + +type ClobStagedFinalizeBlockEvent_CreateClobPair struct { + CreateClobPair *ClobPair `protobuf:"bytes,1,opt,name=create_clob_pair,json=createClobPair,proto3,oneof" json:"create_clob_pair,omitempty"` +} + +func (*ClobStagedFinalizeBlockEvent_CreateClobPair) isClobStagedFinalizeBlockEvent_Event() {} + +func (m *ClobStagedFinalizeBlockEvent) GetEvent() isClobStagedFinalizeBlockEvent_Event { + if m != nil { + return m.Event + } + return nil +} + +func (m *ClobStagedFinalizeBlockEvent) GetCreateClobPair() *ClobPair { + if x, ok := m.GetEvent().(*ClobStagedFinalizeBlockEvent_CreateClobPair); ok { + return x.CreateClobPair + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ClobStagedFinalizeBlockEvent) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ClobStagedFinalizeBlockEvent_CreateClobPair)(nil), + } +} + +func init() { + proto.RegisterType((*ClobStagedFinalizeBlockEvent)(nil), "dydxprotocol.clob.ClobStagedFinalizeBlockEvent") +} + +func init() { + proto.RegisterFile("dydxprotocol/clob/finalize_block.proto", fileDescriptor_ce1d49660993e938) +} + +var fileDescriptor_ce1d49660993e938 = []byte{ + // 219 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4b, 0xa9, 0x4c, 0xa9, + 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x4f, 0xce, 0xc9, 0x4f, 0xd2, 0x4f, 0xcb, + 0xcc, 0x4b, 0xcc, 0xc9, 0xac, 0x4a, 0x8d, 0x4f, 0xca, 0xc9, 0x4f, 0xce, 0xd6, 0x03, 0x4b, 0x0a, + 0x09, 0x22, 0xab, 0xd3, 0x03, 0xa9, 0x93, 0x52, 0xc4, 0xd4, 0x0a, 0x22, 0xe2, 0x0b, 0x12, 0x33, + 0x8b, 0x20, 0xba, 0x94, 0x0a, 0xb8, 0x64, 0x9c, 0x73, 0xf2, 0x93, 0x82, 0x4b, 0x12, 0xd3, 0x53, + 0x53, 0xdc, 0xa0, 0xe6, 0x3a, 0x81, 0x8c, 0x75, 0x2d, 0x4b, 0xcd, 0x2b, 0x11, 0x72, 0xe7, 0x12, + 0x48, 0x2e, 0x4a, 0x4d, 0x2c, 0x49, 0x8d, 0x87, 0xeb, 0x94, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x36, + 0x92, 0xd6, 0xc3, 0xb0, 0x50, 0x0f, 0x64, 0x54, 0x40, 0x62, 0x66, 0x91, 0x07, 0x43, 0x10, 0x1f, + 0x44, 0x1b, 0x4c, 0xc4, 0x89, 0x9d, 0x8b, 0x35, 0x15, 0x64, 0xa2, 0x53, 0xc0, 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, 0x99, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, + 0xe7, 0xe7, 0xea, 0xa3, 0xb8, 0xbc, 0xcc, 0x44, 0x37, 0x39, 0x23, 0x31, 0x33, 0x4f, 0x1f, 0x2e, + 0x52, 0x01, 0xf1, 0x4d, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x58, 0xd8, 0x18, 0x10, 0x00, + 0x00, 0xff, 0xff, 0xc0, 0x74, 0xef, 0x17, 0x2a, 0x01, 0x00, 0x00, +} + +func (m *ClobStagedFinalizeBlockEvent) 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 *ClobStagedFinalizeBlockEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ClobStagedFinalizeBlockEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Event != nil { + { + size := m.Event.Size() + i -= size + if _, err := m.Event.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *ClobStagedFinalizeBlockEvent_CreateClobPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ClobStagedFinalizeBlockEvent_CreateClobPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.CreateClobPair != nil { + { + size, err := m.CreateClobPair.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFinalizeBlock(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func encodeVarintFinalizeBlock(dAtA []byte, offset int, v uint64) int { + offset -= sovFinalizeBlock(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ClobStagedFinalizeBlockEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Event != nil { + n += m.Event.Size() + } + return n +} + +func (m *ClobStagedFinalizeBlockEvent_CreateClobPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CreateClobPair != nil { + l = m.CreateClobPair.Size() + n += 1 + l + sovFinalizeBlock(uint64(l)) + } + return n +} + +func sovFinalizeBlock(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozFinalizeBlock(x uint64) (n int) { + return sovFinalizeBlock(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ClobStagedFinalizeBlockEvent) 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 ErrIntOverflowFinalizeBlock + } + 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: ClobStagedFinalizeBlockEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ClobStagedFinalizeBlockEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreateClobPair", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFinalizeBlock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFinalizeBlock + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFinalizeBlock + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ClobPair{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Event = &ClobStagedFinalizeBlockEvent_CreateClobPair{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFinalizeBlock(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFinalizeBlock + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipFinalizeBlock(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, ErrIntOverflowFinalizeBlock + } + 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, ErrIntOverflowFinalizeBlock + } + 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, ErrIntOverflowFinalizeBlock + } + 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, ErrInvalidLengthFinalizeBlock + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupFinalizeBlock + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthFinalizeBlock + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthFinalizeBlock = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowFinalizeBlock = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupFinalizeBlock = fmt.Errorf("proto: unexpected end of group") +) diff --git a/protocol/x/clob/types/keys.go b/protocol/x/clob/types/keys.go index b0b3691612..a78fbea45e 100644 --- a/protocol/x/clob/types/keys.go +++ b/protocol/x/clob/types/keys.go @@ -139,3 +139,9 @@ const ( // This is meant to be used for improved conditional order triggering. MaxTradePricePrefix = "MaxTrade:" ) + +// FinalizeBlock event staging +const ( + StagedEventsCountKey = "StgEvtCnt" + StagedEventsKeyPrefix = "StgEvt:" +) diff --git a/protocol/x/clob/types/memclob.go b/protocol/x/clob/types/memclob.go index 17cbb37601..86191376f7 100644 --- a/protocol/x/clob/types/memclob.go +++ b/protocol/x/clob/types/memclob.go @@ -23,7 +23,7 @@ type MemClob interface { ) MaybeCreateOrderbook( clobPair ClobPair, - ) + ) bool GetOperationsToReplay( ctx sdk.Context, ) ( diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 54cab6e467..4e116b044e 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -5,7 +5,6 @@ import ( "math" "math/big" - "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/lib/slinky" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" @@ -90,33 +89,19 @@ func (k Keeper) CreateClobPair( ) (clobPairId uint32, err error) { clobPairId = k.ClobKeeper.AcquireNextClobPairID(ctx) - clobPair := clobtypes.ClobPair{ - Metadata: &clobtypes.ClobPair_PerpetualClobMetadata{ - PerpetualClobMetadata: &clobtypes.PerpetualClobMetadata{ - PerpetualId: perpetualId, - }, - }, - Id: clobPairId, - StepBaseQuantums: types.DefaultStepBaseQuantums, - QuantumConversionExponent: types.DefaultQuantumConversionExponent, - SubticksPerTick: types.SubticksPerTick_LongTail, - Status: clobtypes.ClobPair_STATUS_ACTIVE, - } - if err := k.ClobKeeper.ValidateClobPairCreation(ctx, &clobPair); err != nil { + clobPair, err := k.ClobKeeper.CreatePerpetualClobPair( + ctx, + clobPairId, + perpetualId, + satypes.BaseQuantums(types.DefaultStepBaseQuantums), + types.DefaultQuantumConversionExponent, + types.SubticksPerTick_LongTail, + clobtypes.ClobPair_STATUS_ACTIVE, + ) + if err != nil { return 0, err } - k.ClobKeeper.SetClobPair(ctx, clobPair) - - // Only create the clob pair if we are in deliver tx mode. This is to prevent populating - // in memory data structures in the CLOB during simulation mode. - if lib.IsDeliverTxMode(ctx) { - err := k.ClobKeeper.CreateClobPairStructures(ctx, clobPair) - if err != nil { - return 0, err - } - } - return clobPair.Id, nil } diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index b806e91a79..656fb14aad 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -12,6 +12,7 @@ import ( asstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" @@ -234,7 +235,7 @@ func TestCreateClobPair(t *testing.T) { // Set deliverTx mode if tc.isDeliverTx { - ctx = ctx.WithIsCheckTx(false).WithIsReCheckTx(false) + ctx = ctx.WithIsCheckTx(false).WithIsReCheckTx(false).WithExecMode(sdk.ExecModeFinalize) lib.AssertDeliverTxMode(ctx) } else { ctx = ctx.WithIsCheckTx(true) @@ -293,12 +294,21 @@ func TestCreateClobPair(t *testing.T) { ) require.Equal(t, perpetualId, clobPair.MustGetPerpetualId()) - // Check if the clob pair was created only if we are in deliverTx mode + // Should not modify in-memory object right away _, found = clobKeeper.PerpetualIdToClobPairId[perpetualId] + require.False(t, found) + + // Check the corresponding ClobPair creation was staged. + stagedEvents := clobKeeper.GetStagedClobFinalizeBlockEvents(ctx) + if tc.isDeliverTx { - require.True(t, found) + require.Equal(t, 1, len(stagedEvents)) + require.Equal(t, + stagedEvents[0].GetCreateClobPair().GetPerpetualClobMetadata().PerpetualId, + perpetualId, + ) } else { - require.False(t, found) + require.Equal(t, 0, len(stagedEvents)) } }, ) @@ -378,6 +388,7 @@ func TestDepositToMegavaultforPML(t *testing.T) { return genesis }, ).Build() + ctx := tApp.InitChain() // Set existing total shares. diff --git a/protocol/x/listing/types/expected_keepers.go b/protocol/x/listing/types/expected_keepers.go index 7676db370e..e5a8b6693a 100644 --- a/protocol/x/listing/types/expected_keepers.go +++ b/protocol/x/listing/types/expected_keepers.go @@ -35,8 +35,9 @@ type ClobKeeper interface { ) (clobtypes.ClobPair, error) AcquireNextClobPairID(ctx sdk.Context) uint32 ValidateClobPairCreation(ctx sdk.Context, clobPair *clobtypes.ClobPair) error - CreateClobPairStructures(ctx sdk.Context, clobPair clobtypes.ClobPair) error + StageNewClobPairSideEffects(ctx sdk.Context, clobPair clobtypes.ClobPair) error SetClobPair(ctx sdk.Context, clobPair clobtypes.ClobPair) + GetStagedClobFinalizeBlockEvents(ctx sdk.Context) []*clobtypes.ClobStagedFinalizeBlockEvent } type MarketMapKeeper interface { From ffa2efcb5e9ea67f6fae723a86f183c1a0148279 Mon Sep 17 00:00:00 2001 From: Tian Date: Thu, 3 Oct 2024 16:51:16 -0400 Subject: [PATCH 078/120] in testing, megavault main subaccount has 0 usdc by default (#2462) --- protocol/testing/genesis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index 5a428f3e28..c08b293943 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -23,7 +23,7 @@ DEFAULT_SUBACCOUNT_QUOTE_BALANCE=100000000000000000 DEFAULT_SUBACCOUNT_QUOTE_BALANCE_FAUCET=900000000000000000 DEFAULT_SUBACCOUNT_QUOTE_BALANCE_VAULT=1000000000 MEGAVAULT_MAIN_VAULT_ACCOUNT_ADDR="dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r" -DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE=1000000000000 # 1 million USDC +DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE=0 # 0 USDC NATIVE_TOKEN_WHOLE_COIN="dv4tnt" COIN_NAME="dYdX V4 Testnet Token" # Each testnet validator has 1 million whole coins of native token. From c171a0d150771f978b549fbda6d010d3da69c358 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Thu, 3 Oct 2024 17:06:09 -0400 Subject: [PATCH 079/120] Update sidecar to connect v2 (#2458) --- protocol/contrib/{slinky => connect}/oracle.json | 0 protocol/contrib/prometheus/prometheus.yml | 2 +- protocol/docker-compose.yml | 14 +++++++------- protocol/testing/testnet-local/local.sh | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) rename protocol/contrib/{slinky => connect}/oracle.json (100%) diff --git a/protocol/contrib/slinky/oracle.json b/protocol/contrib/connect/oracle.json similarity index 100% rename from protocol/contrib/slinky/oracle.json rename to protocol/contrib/connect/oracle.json diff --git a/protocol/contrib/prometheus/prometheus.yml b/protocol/contrib/prometheus/prometheus.yml index a5205fdd47..5409a1df3d 100644 --- a/protocol/contrib/prometheus/prometheus.yml +++ b/protocol/contrib/prometheus/prometheus.yml @@ -4,4 +4,4 @@ global: scrape_configs: - job_name: "prometheus" static_configs: - - targets: ["slinky0:8002"] # ingest side-car metrics in accordance w/ docker-compose env + - targets: ["connect0:8002"] # ingest side-car metrics in accordance w/ docker-compose env diff --git a/protocol/docker-compose.yml b/protocol/docker-compose.yml index 8ecf83b8bc..7314dee56b 100644 --- a/protocol/docker-compose.yml +++ b/protocol/docker-compose.yml @@ -115,16 +115,16 @@ services: - DAEMON_HOME=/dydxprotocol/chain/.dave volumes: - ./localnet/dydxprotocol3:/dydxprotocol/chain/.dave/data - slinky0: - image: ghcr.io/skip-mev/slinky-sidecar:v1.0.10 + connect0: + image: ghcr.io/skip-mev/connect-sidecar:v2.1.0 entrypoint: > - sh -c "slinky --marketmap-provider dydx_migration_api --oracle-config /etc/slinky/oracle.json --log-std-out-level error" + sh -c "connect --marketmap-provider dydx_migration_api --oracle-config /etc/connect/oracle.json --log-std-out-level error" environment: - - SLINKY_CONFIG_PROVIDERS_RAYDIUM_API_API_ENDPOINTS_0_URL=${RAYDIUM_URL} - - SLINKY_CONFIG_PROVIDERS_UNISWAPV3_API-BASE_API_ENDPOINTS_0_URL=${UNISWAPV3_BASE_URL} - - SLINKY_CONFIG_PROVIDERS_UNISWAPV3_API-ETHEREUM_API_ENDPOINTS_0_URL=${UNISWAPV3_ETHEREUM_URL} + - CONNECT_CONFIG_PROVIDERS_RAYDIUM_API_API_ENDPOINTS_0_URL=${RAYDIUM_URL} + - CONNECT_CONFIG_PROVIDERS_UNISWAPV3_API-BASE_API_ENDPOINTS_0_URL=${UNISWAPV3_BASE_URL} + - CONNECT_CONFIG_PROVIDERS_UNISWAPV3_API-ETHEREUM_API_ENDPOINTS_0_URL=${UNISWAPV3_ETHEREUM_URL} volumes: - - ./contrib/slinky:/etc/slinky + - ./contrib/connect:/etc/connect ports: - "8080:8080" - "8002:8002" # metrics diff --git a/protocol/testing/testnet-local/local.sh b/protocol/testing/testnet-local/local.sh index a90bc06c0d..d11ad734d8 100755 --- a/protocol/testing/testnet-local/local.sh +++ b/protocol/testing/testnet-local/local.sh @@ -107,7 +107,7 @@ create_validators() { cat <<<"$new_file" >"$VAL_CONFIG_DIR"/node_key.json edit_config "$VAL_CONFIG_DIR" - use_slinky "$VAL_CONFIG_DIR" + use_connect "$VAL_CONFIG_DIR" # Using "*" as a subscript results in a single arg: "dydx1... dydx1... dydx1..." # Using "@" as a subscript results in separate args: "dydx1..." "dydx1..." "dydx1..." @@ -167,11 +167,11 @@ setup_cosmovisor() { done } -use_slinky() { +use_connect() { CONFIG_FOLDER=$1 # Enable slinky daemon dasel put -t bool -f "$CONFIG_FOLDER"/app.toml 'oracle.enabled' -v true - dasel put -t string -f "$VAL_CONFIG_DIR"/app.toml 'oracle.oracle_address' -v 'slinky0:8080' + dasel put -t string -f "$VAL_CONFIG_DIR"/app.toml 'oracle.oracle_address' -v 'connect0:8080' } # TODO(DEC-1894): remove this function once we migrate off of persistent peers. From 82fcd790d0a51c0e0eb76507370f19d40dfee90c Mon Sep 17 00:00:00 2001 From: Tian Date: Thu, 3 Oct 2024 17:30:27 -0400 Subject: [PATCH 080/120] don't initialize megavault subaccount if balance is 0 in genesis (#2464) --- protocol/testing/genesis.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index c08b293943..bf7a99cf2c 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -1827,9 +1827,11 @@ function edit_genesis() { acct_idx=$(($acct_idx + 1)) done # Update subaccounts module for megavault main vault account. - add_subaccount "$GENESIS" "$acct_idx" "$MEGAVAULT_MAIN_VAULT_ACCOUNT_ADDR" "$DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE" - total_accounts_quote_balance=$(($total_accounts_quote_balance + $DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE)) - acct_idx=$(($acct_idx + 1)) + if [ "$DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE" -gt 0 ]; then + add_subaccount "$GENESIS" "$acct_idx" "$MEGAVAULT_MAIN_VAULT_ACCOUNT_ADDR" "$DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE" + total_accounts_quote_balance=$(($total_accounts_quote_balance + $DEFAULT_MEGAVAULT_MAIN_VAULT_QUOTE_BALANCE)) + acct_idx=$(($acct_idx + 1)) + fi next_bank_idx=0 if (( total_accounts_quote_balance > 0 )); then From 15621ced89475a91ace6025850b2af096434d9b8 Mon Sep 17 00:00:00 2001 From: Tian Date: Thu, 3 Oct 2024 17:45:42 -0400 Subject: [PATCH 081/120] remove megavault subaccount from sample pregenesis (#2467) --- protocol/scripts/genesis/sample_pregenesis.json | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index 34c0e49637..21ebb6f93d 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -3948,22 +3948,7 @@ } }, "subaccounts": { - "subaccounts": [ - { - "asset_positions": [ - { - "asset_id": 0, - "index": 0, - "quantums": "1000000000000" - } - ], - "id": { - "number": 0, - "owner": "dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r" - }, - "margin_enabled": true - } - ] + "subaccounts": [] }, "transfer": { "denom_traces": [], From 2b50df02fb0c4c33aff88a5062e5e07b267bc952 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:25:20 -0400 Subject: [PATCH 082/120] [CT-1262] add e2e tests for new auth flow failure cases (#2461) --- protocol/app/app.go | 13 +- protocol/testutil/app/app.go | 6 +- protocol/testutil/constants/genesis.go | 8 + .../x/accountplus/authenticator/all_of.go | 7 +- .../x/accountplus/authenticator/any_of.go | 4 +- .../authenticator/clob_pair_id_filter.go | 3 +- .../authenticator/clob_pair_id_filter_test.go | 4 +- .../x/accountplus/authenticator/composite.go | 9 +- .../authenticator/composition_test.go | 20 +- .../authenticator/message_filter.go | 3 +- .../authenticator/message_filter_test.go | 4 +- .../authenticator/signature_authenticator.go | 2 +- .../authenticator/subaccount_filter.go | 3 +- .../authenticator/subaccount_filter_test.go | 4 +- protocol/x/accountplus/types/errors.go | 32 + protocol/x/accountplus/types/iface.go | 5 + .../types/message_add_authenticator.go | 6 +- .../types/message_add_authenticator_test.go | 18 +- protocol/x/clob/e2e/permissioned_keys_test.go | 664 ++++++++++++++++++ 19 files changed, 775 insertions(+), 40 deletions(-) create mode 100644 protocol/x/clob/e2e/permissioned_keys_test.go diff --git a/protocol/app/app.go b/protocol/app/app.go index 5b4e38955a..4e974025f4 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1233,9 +1233,16 @@ func New( // Initialize authenticators app.AuthenticatorManager = authenticator.NewAuthenticatorManager() - app.AuthenticatorManager.InitializeAuthenticators([]accountplusmoduletypes.Authenticator{ - authenticator.NewSignatureVerification(app.AccountKeeper), - }) + app.AuthenticatorManager.InitializeAuthenticators( + []accountplusmoduletypes.Authenticator{ + authenticator.NewAllOf(app.AuthenticatorManager), + authenticator.NewAnyOf(app.AuthenticatorManager), + authenticator.NewSignatureVerification(app.AccountKeeper), + authenticator.NewMessageFilter(), + authenticator.NewClobPairIdFilter(), + authenticator.NewSubaccountFilter(), + }, + ) app.AccountPlusKeeper = *accountplusmodulekeeper.NewKeeper( appCodec, keys[accountplusmoduletypes.StoreKey], diff --git a/protocol/testutil/app/app.go b/protocol/testutil/app/app.go index 40de56f9e2..a4dbac0bc2 100644 --- a/protocol/testutil/app/app.go +++ b/protocol/testutil/app/app.go @@ -49,6 +49,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/testutil/appoptions" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" testlog "github.com/dydxprotocol/v4-chain/protocol/testutil/logger" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" blocktimetypes "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/types" bridgetypes "github.com/dydxprotocol/v4-chain/protocol/x/bridge/types" @@ -207,7 +208,8 @@ type GenesisStates interface { govplus.GenesisState | vaulttypes.GenesisState | revsharetypes.GenesisState | - marketmapmoduletypes.GenesisState + marketmapmoduletypes.GenesisState | + aptypes.GenesisState } // UpdateGenesisDocWithAppStateForModule updates the supplied genesis doc using the provided function. The function @@ -269,6 +271,8 @@ func UpdateGenesisDocWithAppStateForModule[T GenesisStates](genesisDoc *types.Ge moduleName = marketmapmoduletypes.ModuleName case listingtypes.GenesisState: moduleName = listingtypes.ModuleName + case aptypes.GenesisState: + moduleName = aptypes.ModuleName default: panic(fmt.Errorf("Unsupported type %T", t)) } diff --git a/protocol/testutil/constants/genesis.go b/protocol/testutil/constants/genesis.go index 2c679ec3ed..ba7c2f1402 100644 --- a/protocol/testutil/constants/genesis.go +++ b/protocol/testutil/constants/genesis.go @@ -442,6 +442,14 @@ const GenesisState = `{ "validator_historical_rewards": [], "validator_slash_events": [] }, + "dydxaccountplus": { + "accounts": [], + "params": { + "is_smart_account_active": false + }, + "next_authenticator_id": "0", + "authenticator_data": [] + }, "epochs": { "epoch_info_list": [ { diff --git a/protocol/x/accountplus/authenticator/all_of.go b/protocol/x/accountplus/authenticator/all_of.go index 34460098cc..8f8b13bebc 100644 --- a/protocol/x/accountplus/authenticator/all_of.go +++ b/protocol/x/accountplus/authenticator/all_of.go @@ -49,7 +49,7 @@ func (aoa AllOf) StaticGas() uint64 { } func (aoa AllOf) Initialize(config []byte) (types.Authenticator, error) { - var initDatas []SubAuthenticatorInitData + var initDatas []types.SubAuthenticatorInitData if err := json.Unmarshal(config, &initDatas); err != nil { return nil, errorsmod.Wrap(err, "failed to parse sub-authenticators initialization data") } @@ -99,7 +99,10 @@ func (aoa AllOf) Authenticate(ctx sdk.Context, request types.AuthenticationReque request.Signature = signatures[i] } if err := auth.Authenticate(ctx, request); err != nil { - return err + return errorsmod.Wrap( + types.ErrAllOfVerification, + err.Error(), + ) } } return nil diff --git a/protocol/x/accountplus/authenticator/any_of.go b/protocol/x/accountplus/authenticator/any_of.go index 325834268a..c51dfa80f0 100644 --- a/protocol/x/accountplus/authenticator/any_of.go +++ b/protocol/x/accountplus/authenticator/any_of.go @@ -60,7 +60,7 @@ func (aoa AnyOf) StaticGas() uint64 { func (aoa AnyOf) Initialize(config []byte) (types.Authenticator, error) { // Decode the initialization data for each sub-authenticator - var initDatas []SubAuthenticatorInitData + var initDatas []types.SubAuthenticatorInitData if err := json.Unmarshal(config, &initDatas); err != nil { return nil, errorsmod.Wrap(err, "failed to parse sub-authenticators initialization data") } @@ -126,7 +126,7 @@ func (aoa AnyOf) Authenticate(ctx sdk.Context, request types.AuthenticationReque if err != nil { // return all errors return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, + types.ErrAnyOfVerification, "all sub-authenticators failed to authenticate: %s", strings.Join(subAuthErrors, "; "), ) diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go index 2a20762952..bdf3841384 100644 --- a/protocol/x/accountplus/authenticator/clob_pair_id_filter.go +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter.go @@ -6,7 +6,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ) @@ -77,7 +76,7 @@ func (m ClobPairIdFilter) Authenticate(ctx sdk.Context, request types.Authentica for _, clobPairId := range requestOrderIds { if _, ok := m.whitelist[clobPairId]; !ok { return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, + types.ErrClobPairIdVerification, "order id %d not in whitelist %v", clobPairId, m.whitelist, diff --git a/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go index 948f588b5a..86802677c5 100644 --- a/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go +++ b/protocol/x/accountplus/authenticator/clob_pair_id_filter_test.go @@ -6,11 +6,11 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/stretchr/testify/suite" ) @@ -105,7 +105,7 @@ func (s *ClobPairIdFilterTest) TestFilter() { if tt.match { s.Require().NoError(err) } else { - s.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) + s.Require().ErrorIs(err, types.ErrClobPairIdVerification) } }) } diff --git a/protocol/x/accountplus/authenticator/composite.go b/protocol/x/accountplus/authenticator/composite.go index b49000fb42..babbfbffae 100644 --- a/protocol/x/accountplus/authenticator/composite.go +++ b/protocol/x/accountplus/authenticator/composite.go @@ -10,11 +10,6 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) -type SubAuthenticatorInitData struct { - Type string `json:"type"` - Config []byte `json:"config"` -} - func subTrack( ctx sdk.Context, request types.AuthenticationRequest, @@ -50,7 +45,7 @@ func onSubAuthenticatorsAdded( authenticatorId string, am *AuthenticatorManager, ) error { - var initDatas []SubAuthenticatorInitData + var initDatas []types.SubAuthenticatorInitData if err := json.Unmarshal(data, &initDatas); err != nil { return errorsmod.Wrapf(err, "failed to unmarshal sub-authenticator init data") } @@ -97,7 +92,7 @@ func onSubAuthenticatorsRemoved( authenticatorId string, am *AuthenticatorManager, ) error { - var initDatas []SubAuthenticatorInitData + var initDatas []types.SubAuthenticatorInitData if err := json.Unmarshal(data, &initDatas); err != nil { return err } diff --git a/protocol/x/accountplus/authenticator/composition_test.go b/protocol/x/accountplus/authenticator/composition_test.go index 01b3f1a315..b05335b564 100644 --- a/protocol/x/accountplus/authenticator/composition_test.go +++ b/protocol/x/accountplus/authenticator/composition_test.go @@ -187,9 +187,9 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOf() { for _, tc := range testCases { s.T().Run(tc.name, func(t *testing.T) { // Convert the authenticators to InitializationData - initData := []authenticator.SubAuthenticatorInitData{} + initData := []types.SubAuthenticatorInitData{} for _, auth := range tc.authenticators { - initData = append(initData, authenticator.SubAuthenticatorInitData{ + initData = append(initData, types.SubAuthenticatorInitData{ Type: auth.Type(), Config: testData, }) @@ -344,9 +344,9 @@ func (s *AggregatedAuthenticatorsTest) TestAllOf() { for _, tc := range testCases { s.T().Run(tc.name, func(t *testing.T) { // Convert the authenticators to InitializationData - initData := []authenticator.SubAuthenticatorInitData{} + initData := []types.SubAuthenticatorInitData{} for _, auth := range tc.authenticators { - initData = append(initData, authenticator.SubAuthenticatorInitData{ + initData = append(initData, types.SubAuthenticatorInitData{ Type: auth.Type(), Config: testData, }) @@ -562,14 +562,14 @@ func (csa *CompositeSpyAuth) buildInitData() ([]byte, error) { } return json.Marshal(spyData) } else if len(csa.anyOf) > 0 { - var initData []authenticator.SubAuthenticatorInitData + var initData []types.SubAuthenticatorInitData for _, subAuth := range csa.anyOf { data, err := subAuth.buildInitData() if err != nil { return nil, err } - initData = append(initData, authenticator.SubAuthenticatorInitData{ + initData = append(initData, types.SubAuthenticatorInitData{ Type: subAuth.Type(), Config: data, }) @@ -577,14 +577,14 @@ func (csa *CompositeSpyAuth) buildInitData() ([]byte, error) { return json.Marshal(initData) } else if len(csa.allOf) > 0 { - var initData []authenticator.SubAuthenticatorInitData + var initData []types.SubAuthenticatorInitData for _, subAuth := range csa.allOf { data, err := subAuth.buildInitData() if err != nil { return nil, err } - initData = append(initData, authenticator.SubAuthenticatorInitData{ + initData = append(initData, types.SubAuthenticatorInitData{ Type: subAuth.Type(), Config: data, }) @@ -901,14 +901,14 @@ func (s *AggregatedAuthenticatorsTest) TestAnyOfNotWritingFailedSubAuthState() { } func marshalAuth(ta testAuth, testData []byte) ([]byte, error) { - initData := []authenticator.SubAuthenticatorInitData{} + initData := []types.SubAuthenticatorInitData{} for _, sub := range ta.subAuths { subData, err := marshalAuth(sub, testData) if err != nil { return nil, err } - initData = append(initData, authenticator.SubAuthenticatorInitData{ + initData = append(initData, types.SubAuthenticatorInitData{ Type: sub.authenticator.Type(), Config: subData, }) diff --git a/protocol/x/accountplus/authenticator/message_filter.go b/protocol/x/accountplus/authenticator/message_filter.go index a8bc467aad..96ae8c533a 100644 --- a/protocol/x/accountplus/authenticator/message_filter.go +++ b/protocol/x/accountplus/authenticator/message_filter.go @@ -6,7 +6,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" ) @@ -54,7 +53,7 @@ func (m MessageFilter) Track(ctx sdk.Context, request types.AuthenticationReques func (m MessageFilter) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { if _, ok := m.whitelist[sdk.MsgTypeURL(request.Msg)]; !ok { return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, + types.ErrMessageTypeVerification, "message types do not match. Got %s, Expected %v", sdk.MsgTypeURL(request.Msg), m.whitelist, diff --git a/protocol/x/accountplus/authenticator/message_filter_test.go b/protocol/x/accountplus/authenticator/message_filter_test.go index 42c5edc925..b39abf57cc 100644 --- a/protocol/x/accountplus/authenticator/message_filter_test.go +++ b/protocol/x/accountplus/authenticator/message_filter_test.go @@ -6,13 +6,13 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" bank "github.com/cosmos/cosmos-sdk/x/bank/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/stretchr/testify/suite" ) @@ -121,7 +121,7 @@ func (s *MessageFilterTest) TestBankSend() { if tt.match { s.Require().NoError(err) } else { - s.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) + s.Require().ErrorIs(err, types.ErrMessageTypeVerification) } }) } diff --git a/protocol/x/accountplus/authenticator/signature_authenticator.go b/protocol/x/accountplus/authenticator/signature_authenticator.go index e3ecce10de..9e7d759cd9 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator.go @@ -65,7 +65,7 @@ func (sva SignatureVerification) Authenticate(ctx sdk.Context, request types.Aut if !sva.PubKey.VerifySignature(request.SignModeTxData.Direct, request.Signature) { return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, + types.ErrSignatureVerification, "signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", request.TxData.AccountNumber, request.TxData.AccountSequence, diff --git a/protocol/x/accountplus/authenticator/subaccount_filter.go b/protocol/x/accountplus/authenticator/subaccount_filter.go index c36290bc31..7e9ea984d7 100644 --- a/protocol/x/accountplus/authenticator/subaccount_filter.go +++ b/protocol/x/accountplus/authenticator/subaccount_filter.go @@ -6,7 +6,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" ) @@ -75,7 +74,7 @@ func (m SubaccountFilter) Authenticate(ctx sdk.Context, request types.Authentica for _, subaccountNum := range requestSubaccountNums { if _, ok := m.whitelist[subaccountNum]; !ok { return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, + types.ErrSubaccountVerification, "subaccount number %d not in whitelist %v", subaccountNum, m.whitelist, diff --git a/protocol/x/accountplus/authenticator/subaccount_filter_test.go b/protocol/x/accountplus/authenticator/subaccount_filter_test.go index 09f6e85eb8..2221d2adaa 100644 --- a/protocol/x/accountplus/authenticator/subaccount_filter_test.go +++ b/protocol/x/accountplus/authenticator/subaccount_filter_test.go @@ -6,11 +6,11 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/authenticator" "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/stretchr/testify/suite" ) @@ -105,7 +105,7 @@ func (s *SubaccountFilterTest) TestFilter() { if tt.match { s.Require().NoError(err) } else { - s.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) + s.Require().ErrorIs(err, types.ErrSubaccountVerification) } }) } diff --git a/protocol/x/accountplus/types/errors.go b/protocol/x/accountplus/types/errors.go index 9307876c66..347334b2e2 100644 --- a/protocol/x/accountplus/types/errors.go +++ b/protocol/x/accountplus/types/errors.go @@ -33,4 +33,36 @@ var ( 6, "The transaction has multiple signers", ) + + // Errors for failing authenticator validation + ErrSignatureVerification = errorsmod.Register( + ModuleName, + 100, + "Signature verification failed", + ) + ErrMessageTypeVerification = errorsmod.Register( + ModuleName, + 101, + "Message type verification failed", + ) + ErrClobPairIdVerification = errorsmod.Register( + ModuleName, + 102, + "Clob pair id verification failed", + ) + ErrSubaccountVerification = errorsmod.Register( + ModuleName, + 103, + "Subaccount verification failed", + ) + ErrAllOfVerification = errorsmod.Register( + ModuleName, + 104, + "AllOf verification failed", + ) + ErrAnyOfVerification = errorsmod.Register( + ModuleName, + 105, + "AnyOf verification failed", + ) ) diff --git a/protocol/x/accountplus/types/iface.go b/protocol/x/accountplus/types/iface.go index b1a048cfdc..53d21a6ed4 100644 --- a/protocol/x/accountplus/types/iface.go +++ b/protocol/x/accountplus/types/iface.go @@ -10,6 +10,11 @@ type InitializedAuthenticator struct { Authenticator Authenticator } +type SubAuthenticatorInitData struct { + Type string `json:"type"` + Config []byte `json:"config"` +} + // Authenticator is an interface that encapsulates all authentication functionalities essential for // verifying transactions, paying transaction fees, and managing gas consumption during verification. type Authenticator interface { diff --git a/protocol/x/accountplus/types/message_add_authenticator.go b/protocol/x/accountplus/types/message_add_authenticator.go index 557d3796a8..f70b178d26 100644 --- a/protocol/x/accountplus/types/message_add_authenticator.go +++ b/protocol/x/accountplus/types/message_add_authenticator.go @@ -4,7 +4,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -const AUTHENTICATOR_DATA_MAX_LENGTH = 256 +// AUTHENTICATOR_DATA_MAX_LENGTH is the maximum length of the data field in an authenticator. +// +// This is used as a light-weight spam mitigation measure to prevent users from adding +// arbitrarily complex authenticators that are too resource intensive. +const AUTHENTICATOR_DATA_MAX_LENGTH = 1024 // ValidateBasic performs stateless validation for the `MsgAddAuthenticator` msg. func (msg *MsgAddAuthenticator) ValidateBasic() (err error) { diff --git a/protocol/x/accountplus/types/message_add_authenticator_test.go b/protocol/x/accountplus/types/message_add_authenticator_test.go index cc818ffad2..9a0c056486 100644 --- a/protocol/x/accountplus/types/message_add_authenticator_test.go +++ b/protocol/x/accountplus/types/message_add_authenticator_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestMsgCompleteBridge_ValidateBasic(t *testing.T) { +func TestMsgAddAuthenticator_ValidateBasic(t *testing.T) { const messageFilterData = "/cosmos.bank.v1beta1.MsgMultiSend,/cosmos.bank.v1beta1.MsgSend" tests := map[string]struct { @@ -45,6 +45,14 @@ func TestMsgCompleteBridge_ValidateBasic(t *testing.T) { {"Type":"SignatureVerification","Config":"%s"}, {"Type":"SignatureVerification","Config":"%s"}, {"Type":"SignatureVerification","Config":"%s"} + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"} + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"}, + {"Type":"SignatureVerification","Config":"%s"} ] " }, @@ -54,6 +62,14 @@ func TestMsgCompleteBridge_ValidateBasic(t *testing.T) { constants.BobPrivateKey.PubKey().String(), constants.CarlPrivateKey.PubKey().String(), constants.DavePrivateKey.PubKey().String(), + constants.AlicePrivateKey.PubKey().String(), + constants.BobPrivateKey.PubKey().String(), + constants.CarlPrivateKey.PubKey().String(), + constants.DavePrivateKey.PubKey().String(), + constants.AlicePrivateKey.PubKey().String(), + constants.BobPrivateKey.PubKey().String(), + constants.CarlPrivateKey.PubKey().String(), + constants.DavePrivateKey.PubKey().String(), ), ), }, diff --git a/protocol/x/clob/e2e/permissioned_keys_test.go b/protocol/x/clob/e2e/permissioned_keys_test.go new file mode 100644 index 0000000000..18007beda5 --- /dev/null +++ b/protocol/x/clob/e2e/permissioned_keys_test.go @@ -0,0 +1,664 @@ +package clob_test + +import ( + "encoding/json" + "testing" + + sdkmath "cosmossdk.io/math" + abcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + testtx "github.com/dydxprotocol/v4-chain/protocol/testutil/tx" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" + assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + sendingtypes "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" + "github.com/stretchr/testify/require" +) + +type TestBlockWithMsgs struct { + Block uint32 + Msgs []TestSdkMsg +} + +type TestSdkMsg struct { + Msg []sdk.Msg + Authenticators []uint64 + Fees sdk.Coins + Gas uint64 + AccountNum []uint64 + SeqNum []uint64 + Signers []cryptotypes.PrivKey + + ExpectedRespCode uint32 + ExpectedLog string +} + +func TestPlaceOrder_PermissionedKeys_Failures(t *testing.T) { + config := []aptypes.SubAuthenticatorInitData{ + { + Type: "SignatureVerification", + Config: constants.AlicePrivateKey.PubKey().Bytes(), + }, + { + Type: "MessageFilter", + Config: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + } + compositeAuthenticatorConfig, err := json.Marshal(config) + require.NoError(t, err) + + tests := map[string]struct { + smartAccountEnabled bool + blocks []TestBlockWithMsgs + + expectedOrderIdsInMemclob map[clobtypes.OrderId]bool + }{ + "Txn has authenticators specified, but smart account is not enabled": { + smartAccountEnabled: false, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrSmartAccountNotActive.ABCICode(), + ExpectedLog: aptypes.ErrSmartAccountNotActive.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn has authenticators specified, but authenticator is not found": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrAuthenticatorNotFound.ABCICode(), + ExpectedLog: aptypes.ErrAuthenticatorNotFound.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn has authenticators specified, but authenticator was removed": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "MessageFilter", + Data: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgRemoveAuthenticator{ + Sender: constants.BobAccAddress.String(), + Id: 0, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrAuthenticatorNotFound.ABCICode(), + ExpectedLog: aptypes.ErrAuthenticatorNotFound.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by signature verification authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "SignatureVerification", + // Allow signature verification using Alice's public key. + Data: constants.AlicePrivateKey.PubKey().Bytes(), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrSignatureVerification.ABCICode(), + ExpectedLog: aptypes.ErrSignatureVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by message filter authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "MessageFilter", + Data: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrMessageTypeVerification.ABCICode(), + ExpectedLog: aptypes.ErrMessageTypeVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by clob pair id filter authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "ClobPairIdFilter", + Data: []byte("0"), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrClobPairIdVerification.ABCICode(), + ExpectedLog: aptypes.ErrClobPairIdVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by subaccount number filter authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "SubaccountFilter", + Data: []byte("1"), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrSubaccountVerification.ABCICode(), + ExpectedLog: aptypes.ErrSubaccountVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by all of authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrAllOfVerification.ABCICode(), + ExpectedLog: aptypes.ErrAllOfVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "Txn rejected by any of authenticator": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AnyOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrAnyOfVerification.ABCICode(), + ExpectedLog: aptypes.ErrAnyOfVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + "One of the messages in the transaction is rejected": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "MessageFilter", + Data: []byte("/cosmos.bank.v1beta1.MsgSend"), + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: constants.BobAccAddress.String(), + ToAddress: constants.AliceAccAddress.String(), + Amount: sdk.Coins{sdk.Coin{ + Denom: "foo", + Amount: sdkmath.OneInt(), + }}, + }, + &sendingtypes.MsgCreateTransfer{ + Transfer: &sendingtypes.Transfer{ + Sender: constants.Bob_Num0, + Recipient: constants.Alice_Num0, + AssetId: assettypes.AssetUsdc.Id, + Amount: 500_000_000, // $500 + }, + }, + }, + Authenticators: []uint64{0, 0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: aptypes.ErrMessageTypeVerification.ABCICode(), + ExpectedLog: aptypes.ErrMessageTypeVerification.Error(), + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn(func() (genesis types.GenesisDoc) { + genesis = testapp.DefaultGenesis() + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *aptypes.GenesisState) { + genesisState.Params.IsSmartAccountActive = tc.smartAccountEnabled + }, + ) + return genesis + }).Build() + ctx := tApp.InitChain() + + for _, block := range tc.blocks { + for _, msg := range block.Msgs { + tx, err := testtx.GenTx( + ctx, + tApp.App.TxConfig(), + msg.Msg, + msg.Fees, + msg.Gas, + tApp.App.ChainID(), + msg.AccountNum, + msg.SeqNum, + msg.Signers, + msg.Signers, + msg.Authenticators, + ) + require.NoError(t, err) + + bytes, err := tApp.App.TxConfig().TxEncoder()(tx) + if err != nil { + panic(err) + } + checkTxReq := abcitypes.RequestCheckTx{ + Tx: bytes, + Type: abcitypes.CheckTxType_New, + } + + resp := tApp.CheckTx(checkTxReq) + require.Equal( + t, + msg.ExpectedRespCode, + resp.Code, + "Response code was not as expected", + ) + require.Contains( + t, + resp.Log, + msg.ExpectedLog, + "Response log was not as expected", + ) + } + ctx = tApp.AdvanceToBlock(block.Block, testapp.AdvanceToBlockOptions{}) + } + + for orderId, shouldHaveOrder := range tc.expectedOrderIdsInMemclob { + _, exists := tApp.App.ClobKeeper.MemClob.GetOrder(orderId) + require.Equal(t, shouldHaveOrder, exists) + } + }) + } +} From 75a93ebbd041cf832a18913a670d5c3d5910517c Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Mon, 14 Oct 2024 14:29:44 -0400 Subject: [PATCH 083/120] [OTE-852] Register rpc routes in module (#2480) --- protocol/x/revshare/module.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol/x/revshare/module.go b/protocol/x/revshare/module.go index 460b204145..707347597a 100644 --- a/protocol/x/revshare/module.go +++ b/protocol/x/revshare/module.go @@ -1,6 +1,7 @@ package revshare import ( + "context" "encoding/json" "fmt" @@ -75,7 +76,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} // GetTxCmd returns the root Tx command for the module. The subcommands of this root command are used by end-users to // generate new transactions containing messages defined in the module. From 4eee7a2817aec0e74be1ebf3d41c2efe95ab4a41 Mon Sep 17 00:00:00 2001 From: vincentwschau <99756290+vincentwschau@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:20:57 -0400 Subject: [PATCH 084/120] Fix test flakiness due to using inconsistent time. (#2485) --- indexer/services/comlink/__tests__/lib/helpers.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indexer/services/comlink/__tests__/lib/helpers.test.ts b/indexer/services/comlink/__tests__/lib/helpers.test.ts index 03d169db35..bdbb4e70c3 100644 --- a/indexer/services/comlink/__tests__/lib/helpers.test.ts +++ b/indexer/services/comlink/__tests__/lib/helpers.test.ts @@ -876,7 +876,7 @@ describe('helpers', () => { ), }; const blockHeight2: string = '80'; - const blockTime2: string = DateTime.fromISO(pnlTick.createdAt).plus({ hour: 1 }).toISO(); + const blockTime2: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').plus({ minute: 61 }).toISO(); const pnlTick3: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, id: PnlTicksTable.uuid( @@ -888,7 +888,7 @@ describe('helpers', () => { createdAt: blockTime2, }; const blockHeight3: string = '81'; - const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).plus({ minute: 61 }).toISO(); + const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').plus({ minute: 62 }).toISO(); const pnlTick4: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, subaccountId: testConstants.defaultSubaccountId2, From 353303047552c9c3f7de8017a188482e1ca894e1 Mon Sep 17 00:00:00 2001 From: shrenujb <98204323+shrenujb@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:58:23 -0400 Subject: [PATCH 085/120] Add GRPC gateway route for listing module and add hard cap setting (#2489) Signed-off-by: Shrenuj Bansal --- .../codegen/dydxprotocol/listing/query.lcd.ts | 10 ++- proto/dydxprotocol/listing/query.proto | 5 +- protocol/x/listing/module.go | 5 ++ protocol/x/listing/types/query.pb.go | 23 +++---- protocol/x/listing/types/query.pb.gw.go | 65 +++++++++++++++++++ 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/query.lcd.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/query.lcd.ts index a12d33a4a4..70ab686dfb 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/query.lcd.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/query.lcd.ts @@ -1,5 +1,5 @@ import { LCDClient } from "@osmonauts/lcd"; -import { QueryListingVaultDepositParams, QueryListingVaultDepositParamsResponseSDKType } from "./query"; +import { QueryMarketsHardCap, QueryMarketsHardCapResponseSDKType, QueryListingVaultDepositParams, QueryListingVaultDepositParamsResponseSDKType } from "./query"; export class LCDQueryClient { req: LCDClient; @@ -9,8 +9,16 @@ export class LCDQueryClient { requestClient: LCDClient; }) { this.req = requestClient; + this.marketsHardCap = this.marketsHardCap.bind(this); this.listingVaultDepositParams = this.listingVaultDepositParams.bind(this); } + /* Queries for the hard cap number of listed markets */ + + + async marketsHardCap(_params: QueryMarketsHardCap = {}): Promise { + const endpoint = `dydxprotocol/listing/markets_hard_cap`; + return await this.req.get(endpoint); + } /* Queries the listing vault deposit params */ diff --git a/proto/dydxprotocol/listing/query.proto b/proto/dydxprotocol/listing/query.proto index b200a7637d..cc3616cabd 100644 --- a/proto/dydxprotocol/listing/query.proto +++ b/proto/dydxprotocol/listing/query.proto @@ -10,7 +10,10 @@ option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/listing/types"; // Query defines the gRPC querier service. service Query { // Queries for the hard cap number of listed markets - rpc MarketsHardCap(QueryMarketsHardCap) returns (QueryMarketsHardCapResponse); + rpc MarketsHardCap(QueryMarketsHardCap) + returns (QueryMarketsHardCapResponse) { + option (google.api.http).get = "/dydxprotocol/listing/markets_hard_cap"; + } // Queries the listing vault deposit params rpc ListingVaultDepositParams(QueryListingVaultDepositParams) diff --git a/protocol/x/listing/module.go b/protocol/x/listing/module.go index 819e921c13..99ee5943ed 100644 --- a/protocol/x/listing/module.go +++ b/protocol/x/listing/module.go @@ -1,6 +1,7 @@ package listing import ( + "context" "encoding/json" "fmt" @@ -76,6 +77,10 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } } // GetTxCmd returns the root Tx command for the module. The subcommands of this root command are used by end-users to diff --git a/protocol/x/listing/types/query.pb.go b/protocol/x/listing/types/query.pb.go index 04b32dc0c8..353a7a49ea 100644 --- a/protocol/x/listing/types/query.pb.go +++ b/protocol/x/listing/types/query.pb.go @@ -205,7 +205,7 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/listing/query.proto", fileDescriptor_6c3602ac8eedf7cc) } var fileDescriptor_6c3602ac8eedf7cc = []byte{ - // 365 bytes of a gzipped FileDescriptorProto + // 382 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xa9, 0x4c, 0xa9, 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0xcf, 0xc9, 0x2c, 0x2e, 0xc9, 0xcc, 0x4b, 0xd7, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x03, 0x0b, 0x0b, 0x89, 0x20, 0xab, 0xd0, 0x83, 0xaa, @@ -219,16 +219,17 @@ var fileDescriptor_6c3602ac8eedf7cc = []byte{ 0xe9, 0x03, 0xb1, 0x2d, 0x2c, 0xb1, 0x34, 0xa7, 0xc4, 0x25, 0xb5, 0x20, 0xbf, 0x38, 0xb3, 0x24, 0x00, 0x6c, 0xb1, 0x52, 0x39, 0x97, 0x1a, 0x7e, 0x15, 0x70, 0x6b, 0x7c, 0xb9, 0xd8, 0x20, 0x8e, 0x05, 0x5b, 0xc2, 0x6d, 0xa4, 0xaf, 0x87, 0x2d, 0x68, 0xf4, 0x70, 0x1a, 0xe4, 0xc4, 0x72, 0xe2, - 0x9e, 0x3c, 0x43, 0x10, 0xd4, 0x10, 0xa3, 0xbd, 0x4c, 0x5c, 0xac, 0x60, 0x9b, 0x85, 0xf2, 0xb8, - 0xf8, 0x50, 0x7d, 0x26, 0xa4, 0x89, 0xdd, 0x68, 0x2c, 0x81, 0x20, 0x65, 0x48, 0xb4, 0x52, 0xb8, - 0x47, 0x0e, 0x33, 0x72, 0x49, 0xe2, 0x74, 0xa5, 0x90, 0x09, 0x1e, 0x03, 0x71, 0xea, 0x92, 0xb2, - 0x21, 0x47, 0x17, 0xcc, 0x45, 0x4a, 0x46, 0x4d, 0x97, 0x9f, 0x4c, 0x66, 0xd2, 0x11, 0xd2, 0xd2, - 0xc7, 0x9a, 0x46, 0xca, 0x40, 0x3a, 0xe3, 0x53, 0x20, 0x5a, 0xe3, 0x21, 0xe1, 0xe7, 0x14, 0x7c, - 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, 0x96, 0xe9, 0x99, 0x25, 0x19, 0xa5, - 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xa8, 0xe6, 0x95, 0x99, 0xe8, 0x26, 0x67, 0x24, 0x66, 0xe6, 0xe9, - 0xc3, 0x45, 0x2a, 0xe0, 0x76, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x65, 0x8c, 0x01, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x83, 0xa0, 0xd5, 0x6d, 0x18, 0x03, 0x00, 0x00, + 0x9e, 0x3c, 0x43, 0x10, 0xd4, 0x10, 0xa3, 0x77, 0x4c, 0x5c, 0xac, 0x60, 0x9b, 0x85, 0xe6, 0x31, + 0x72, 0xf1, 0xa1, 0x7a, 0x4d, 0x48, 0x13, 0xbb, 0xd9, 0x58, 0x42, 0x41, 0xca, 0x90, 0x68, 0xa5, + 0x30, 0x9f, 0x28, 0xe9, 0x35, 0x5d, 0x7e, 0x32, 0x99, 0x49, 0x43, 0x48, 0x4d, 0x1f, 0x6b, 0x94, + 0xe4, 0x42, 0x74, 0xc5, 0xc3, 0x02, 0x55, 0xe8, 0x30, 0x23, 0x97, 0x24, 0x4e, 0x6f, 0x09, 0x99, + 0xe0, 0x71, 0x00, 0x4e, 0x5d, 0x52, 0x36, 0xe4, 0xe8, 0x82, 0xfb, 0xc0, 0x08, 0xec, 0x03, 0x1d, + 0x21, 0x2d, 0xec, 0x3e, 0x28, 0x03, 0xe9, 0x8c, 0x4f, 0x81, 0x68, 0x8d, 0x87, 0x04, 0xb8, 0x53, + 0xf0, 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, 0xa6, 0x67, 0x96, 0x64, + 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xa2, 0x9a, 0x57, 0x66, 0xa2, 0x9b, 0x9c, 0x91, 0x98, 0x99, + 0xa7, 0x0f, 0x17, 0xa9, 0x80, 0xdb, 0x51, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x96, 0x31, + 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x73, 0xf2, 0x36, 0x49, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/protocol/x/listing/types/query.pb.gw.go b/protocol/x/listing/types/query.pb.gw.go index e04eaf7961..092dc87e68 100644 --- a/protocol/x/listing/types/query.pb.gw.go +++ b/protocol/x/listing/types/query.pb.gw.go @@ -33,6 +33,24 @@ var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage var _ = metadata.Join +func request_Query_MarketsHardCap_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryMarketsHardCap + var metadata runtime.ServerMetadata + + msg, err := client.MarketsHardCap(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_MarketsHardCap_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryMarketsHardCap + var metadata runtime.ServerMetadata + + msg, err := server.MarketsHardCap(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_ListingVaultDepositParams_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryListingVaultDepositParams var metadata runtime.ServerMetadata @@ -57,6 +75,29 @@ func local_request_Query_ListingVaultDepositParams_0(ctx context.Context, marsha // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + mux.Handle("GET", pattern_Query_MarketsHardCap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_MarketsHardCap_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_MarketsHardCap_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ListingVaultDepositParams_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -121,6 +162,26 @@ func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc // "QueryClient" to call the correct interceptors. func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + mux.Handle("GET", pattern_Query_MarketsHardCap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_MarketsHardCap_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_MarketsHardCap_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ListingVaultDepositParams_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -145,9 +206,13 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( + pattern_Query_MarketsHardCap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "listing", "markets_hard_cap"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ListingVaultDepositParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "listing", "vault_deposit_params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( + forward_Query_MarketsHardCap_0 = runtime.ForwardResponseMessage + forward_Query_ListingVaultDepositParams_0 = runtime.ForwardResponseMessage ) From e085891343fb68a615360e7c29e13868cab9ea93 Mon Sep 17 00:00:00 2001 From: Mohammed Affan Date: Wed, 16 Oct 2024 13:30:49 -0400 Subject: [PATCH 086/120] [OTE-877] deprecate OI indexer update event (#2499) --- .../dydxprotocol/indexer/events/events.ts | 32 +- .../dydxprotocol/indexer/events/events.proto | 4 + protocol/indexer/events/events.pb.go | 316 +++++++++--------- protocol/x/clob/e2e/long_term_orders_test.go | 64 ---- protocol/x/clob/e2e/short_term_orders_test.go | 55 --- protocol/x/perpetuals/abci.go | 1 - protocol/x/perpetuals/abci_test.go | 4 - protocol/x/perpetuals/keeper/perpetual.go | 45 --- .../x/perpetuals/keeper/perpetual_test.go | 26 -- protocol/x/perpetuals/types/types.go | 1 - 10 files changed, 188 insertions(+), 360 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts index 6b968da426..b497e0ec83 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts @@ -1372,31 +1372,47 @@ export interface AddressTradingRewardSDKType { denom_amount: Uint8Array; } -/** OpenInterestUpdateEventV1 is used for open interest update events */ +/** + * OpenInterestUpdateEventV1 is used for open interest update events + * Deprecated. + */ + +/** @deprecated */ export interface OpenInterestUpdateEventV1 { - /** The list of all open interest updates in the block. */ openInterestUpdates: OpenInterestUpdate[]; } -/** OpenInterestUpdateEventV1 is used for open interest update events */ +/** + * OpenInterestUpdateEventV1 is used for open interest update events + * Deprecated. + */ + +/** @deprecated */ export interface OpenInterestUpdateEventV1SDKType { - /** The list of all open interest updates in the block. */ open_interest_updates: OpenInterestUpdateSDKType[]; } -/** OpenInterestUpdate contains a single open interest update for a perpetual */ +/** + * OpenInterestUpdate contains a single open interest update for a perpetual + * Deprecated. + */ + +/** @deprecated */ export interface OpenInterestUpdate { - /** The ID of the perpetual market. */ perpetualId: number; /** The new open interest value for the perpetual market. */ openInterest: Uint8Array; } -/** OpenInterestUpdate contains a single open interest update for a perpetual */ +/** + * OpenInterestUpdate contains a single open interest update for a perpetual + * Deprecated. + */ + +/** @deprecated */ export interface OpenInterestUpdateSDKType { - /** The ID of the perpetual market. */ perpetual_id: number; /** The new open interest value for the perpetual market. */ diff --git a/proto/dydxprotocol/indexer/events/events.proto b/proto/dydxprotocol/indexer/events/events.proto index b152dcd82f..ed555d527e 100644 --- a/proto/dydxprotocol/indexer/events/events.proto +++ b/proto/dydxprotocol/indexer/events/events.proto @@ -534,14 +534,18 @@ message AddressTradingReward { } // OpenInterestUpdateEventV1 is used for open interest update events +// Deprecated. message OpenInterestUpdateEventV1 { // The list of all open interest updates in the block. + option deprecated = true; repeated OpenInterestUpdate open_interest_updates = 1; } // OpenInterestUpdate contains a single open interest update for a perpetual +// Deprecated. message OpenInterestUpdate { // The ID of the perpetual market. + option deprecated = true; uint32 perpetual_id = 1; // The new open interest value for the perpetual market. diff --git a/protocol/indexer/events/events.pb.go b/protocol/indexer/events/events.pb.go index 45c17665b9..4c5fed6d9e 100644 --- a/protocol/indexer/events/events.pb.go +++ b/protocol/indexer/events/events.pb.go @@ -2343,8 +2343,10 @@ func (m *AddressTradingReward) GetOwner() string { } // OpenInterestUpdateEventV1 is used for open interest update events +// Deprecated. +// +// Deprecated: Do not use. type OpenInterestUpdateEventV1 struct { - // The list of all open interest updates in the block. OpenInterestUpdates []*OpenInterestUpdate `protobuf:"bytes,1,rep,name=open_interest_updates,json=openInterestUpdates,proto3" json:"open_interest_updates,omitempty"` } @@ -2389,8 +2391,10 @@ func (m *OpenInterestUpdateEventV1) GetOpenInterestUpdates() []*OpenInterestUpda } // OpenInterestUpdate contains a single open interest update for a perpetual +// Deprecated. +// +// Deprecated: Do not use. type OpenInterestUpdate struct { - // The ID of the perpetual market. PerpetualId uint32 `protobuf:"varint,1,opt,name=perpetual_id,json=perpetualId,proto3" json:"perpetual_id,omitempty"` // The new open interest value for the perpetual market. OpenInterest github_com_dydxprotocol_v4_chain_protocol_dtypes.SerializableInt `protobuf:"bytes,2,opt,name=open_interest,json=openInterest,proto3,customtype=github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt" json:"open_interest"` @@ -2706,160 +2710,160 @@ func init() { } var fileDescriptor_6331dfb59c6fd2bb = []byte{ - // 2439 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcd, 0x6f, 0x23, 0x49, - 0x15, 0x4f, 0xdb, 0x8e, 0xe3, 0x3c, 0xc7, 0x19, 0xbb, 0xc6, 0xc9, 0x38, 0x09, 0xcc, 0x0c, 0x2d, - 0x21, 0x8d, 0xf6, 0xc3, 0x99, 0x09, 0xbb, 0xab, 0xd5, 0x1e, 0x10, 0x71, 0x3e, 0x36, 0x8e, 0x92, - 0x8c, 0xb7, 0xf3, 0xb1, 0xbb, 0x03, 0xda, 0xa6, 0xd2, 0x5d, 0x76, 0x4a, 0xe9, 0xaf, 0xe9, 0x6a, - 0x67, 0x36, 0x83, 0x90, 0x38, 0xb1, 0x1c, 0x90, 0x40, 0x42, 0x1c, 0x38, 0x20, 0x71, 0x81, 0x03, - 0x12, 0x07, 0x24, 0xc4, 0x8d, 0x03, 0xe2, 0xb2, 0x37, 0x56, 0x9c, 0x10, 0x48, 0x2b, 0xb4, 0x7b, - 0xe0, 0xdf, 0x40, 0xf5, 0xd1, 0xed, 0x6f, 0xc7, 0xb3, 0xc9, 0x4a, 0x08, 0x71, 0x8a, 0xeb, 0xbd, - 0x7a, 0xbf, 0xf7, 0xea, 0xbd, 0x57, 0x55, 0xaf, 0x5e, 0x07, 0x1e, 0xd8, 0x97, 0xf6, 0x87, 0x41, - 0xe8, 0x47, 0xbe, 0xe5, 0x3b, 0xab, 0xd4, 0xb3, 0xc9, 0x87, 0x24, 0x5c, 0x25, 0x17, 0xc4, 0x8b, - 0x98, 0xfa, 0x53, 0x15, 0x6c, 0xb4, 0xd2, 0x3d, 0xb3, 0xaa, 0x66, 0x56, 0xe5, 0x94, 0xe5, 0x25, - 0xcb, 0x67, 0xae, 0xcf, 0x4c, 0xc1, 0x5f, 0x95, 0x03, 0x29, 0xb7, 0x5c, 0x6e, 0xf9, 0x2d, 0x5f, - 0xd2, 0xf9, 0x2f, 0x45, 0x7d, 0x38, 0x54, 0x2f, 0x3b, 0xc3, 0x21, 0xb1, 0x57, 0x43, 0xe2, 0xfa, - 0x17, 0xd8, 0x31, 0x43, 0x82, 0x99, 0xef, 0x29, 0x89, 0x97, 0x87, 0x4a, 0x24, 0x84, 0x8b, 0x47, - 0xab, 0x96, 0xe3, 0x9f, 0x8e, 0x85, 0xef, 0x9e, 0x1c, 0x90, 0x30, 0x20, 0x51, 0x1b, 0x3b, 0x4a, - 0xe2, 0xd1, 0x95, 0x12, 0xac, 0x7d, 0x8a, 0x2d, 0xcb, 0x6f, 0x7b, 0x91, 0x12, 0x79, 0xe5, 0x4a, - 0x91, 0x0b, 0xdc, 0x76, 0xd4, 0x6c, 0xfd, 0xaf, 0x1a, 0xdc, 0xda, 0x6e, 0x7b, 0x36, 0xf5, 0x5a, - 0xc7, 0x81, 0x8d, 0x23, 0x72, 0xf2, 0x08, 0x7d, 0x0d, 0xe6, 0x12, 0x3b, 0x4c, 0x6a, 0x57, 0xb4, - 0xfb, 0xda, 0x83, 0x82, 0x91, 0x4f, 0x68, 0x75, 0x1b, 0xbd, 0x04, 0xa5, 0xa6, 0x94, 0x32, 0x2f, - 0xb0, 0xd3, 0x26, 0x66, 0x10, 0xb8, 0x95, 0xd4, 0x7d, 0xed, 0xc1, 0xb4, 0x71, 0x4b, 0x31, 0x4e, - 0x38, 0xbd, 0x11, 0xb8, 0xc8, 0x85, 0x42, 0x3c, 0x57, 0x58, 0x53, 0x49, 0xdf, 0xd7, 0x1e, 0xcc, - 0xd5, 0x76, 0x3e, 0xfe, 0xf4, 0xde, 0xd4, 0x3f, 0x3e, 0xbd, 0xf7, 0xad, 0x16, 0x8d, 0xce, 0xda, - 0xa7, 0x55, 0xcb, 0x77, 0x57, 0x7b, 0x4c, 0xbf, 0x78, 0xed, 0x55, 0xeb, 0x0c, 0x53, 0xaf, 0x63, - 0xbb, 0x1d, 0x5d, 0x06, 0x84, 0x55, 0x0f, 0x49, 0x48, 0xb1, 0x43, 0x9f, 0xe3, 0x53, 0x87, 0xd4, - 0xbd, 0xc8, 0x98, 0x53, 0xf0, 0x75, 0x8e, 0xae, 0xff, 0x2c, 0x05, 0xf3, 0x6a, 0x45, 0x5b, 0x3c, - 0x0d, 0x4e, 0x1e, 0xa1, 0x3d, 0x98, 0x69, 0x8b, 0xc5, 0xb1, 0x8a, 0x76, 0x3f, 0xfd, 0x20, 0xbf, - 0xf6, 0x4a, 0x75, 0x4c, 0xda, 0x54, 0xfb, 0xfc, 0x51, 0xcb, 0x70, 0x4b, 0x8d, 0x18, 0x02, 0x6d, - 0x42, 0x86, 0xdb, 0x21, 0x96, 0x3b, 0xbf, 0xf6, 0x70, 0x12, 0x28, 0x65, 0x48, 0xf5, 0xe8, 0x32, - 0x20, 0x86, 0x90, 0xd6, 0x5d, 0xc8, 0xf0, 0x11, 0x2a, 0x43, 0xf1, 0xe8, 0xfd, 0xc6, 0x96, 0x79, - 0x7c, 0x70, 0xd8, 0xd8, 0xda, 0xa8, 0x6f, 0xd7, 0xb7, 0x36, 0x8b, 0x53, 0xe8, 0x0e, 0xdc, 0x16, - 0xd4, 0x86, 0xb1, 0xb5, 0x5f, 0x3f, 0xde, 0x37, 0x0f, 0xd7, 0xf7, 0x1b, 0x7b, 0x5b, 0x45, 0x0d, - 0xdd, 0x83, 0x15, 0xc1, 0xd8, 0x3e, 0x3e, 0xd8, 0xac, 0x1f, 0xbc, 0x6d, 0x1a, 0xeb, 0x47, 0x5b, - 0xe6, 0xfa, 0xc1, 0xa6, 0x59, 0x3f, 0xd8, 0xdc, 0x7a, 0xaf, 0x98, 0x42, 0x0b, 0x50, 0xea, 0x91, - 0x3c, 0x79, 0x7c, 0xb4, 0x55, 0x4c, 0xeb, 0x7f, 0x49, 0x41, 0x61, 0x1f, 0x87, 0xe7, 0x24, 0x8a, - 0x9d, 0xb2, 0x02, 0xb3, 0xae, 0x20, 0x74, 0x42, 0x9c, 0x93, 0x84, 0xba, 0x8d, 0x9e, 0xc0, 0x5c, - 0x10, 0x52, 0x8b, 0x98, 0x72, 0xd1, 0x62, 0xad, 0xf9, 0xb5, 0xd7, 0xc7, 0xae, 0x55, 0xc2, 0x37, - 0xb8, 0x98, 0x74, 0x9d, 0xd2, 0xb4, 0x33, 0x65, 0xe4, 0x83, 0x0e, 0x15, 0xbd, 0x0b, 0x05, 0xa5, - 0xd8, 0x0a, 0x09, 0x07, 0x4f, 0x0b, 0xf0, 0x87, 0x13, 0x80, 0x6f, 0x08, 0x81, 0x0e, 0xee, 0x9c, - 0xdb, 0x45, 0xee, 0x02, 0x76, 0x7d, 0x9b, 0x36, 0x2f, 0x2b, 0x99, 0x89, 0x81, 0xf7, 0x85, 0xc0, - 0x00, 0xb0, 0x24, 0xd7, 0x66, 0x60, 0x5a, 0xcc, 0xd6, 0x77, 0xa1, 0x32, 0x6a, 0x95, 0xa8, 0x0a, - 0xb7, 0xa5, 0xcb, 0x9e, 0xd1, 0xe8, 0xcc, 0x24, 0x1f, 0x06, 0xbe, 0x47, 0xbc, 0x48, 0x78, 0x36, - 0x63, 0x94, 0x04, 0xeb, 0x5d, 0x1a, 0x9d, 0x6d, 0x29, 0x86, 0xfe, 0x1e, 0x94, 0x24, 0x56, 0x0d, - 0xb3, 0x04, 0x04, 0x41, 0x26, 0xc0, 0x34, 0x14, 0x52, 0xb3, 0x86, 0xf8, 0x8d, 0x56, 0xa1, 0xec, - 0x52, 0xcf, 0x94, 0xe0, 0xd6, 0x19, 0xf6, 0x5a, 0x9d, 0xed, 0x56, 0x30, 0x4a, 0x2e, 0xf5, 0x84, - 0x35, 0x1b, 0x82, 0xd3, 0x08, 0x5c, 0xbd, 0x0d, 0xb7, 0x87, 0xb8, 0x0b, 0xd5, 0x20, 0x73, 0x8a, - 0x19, 0x11, 0xd8, 0xf9, 0xb5, 0xea, 0x04, 0x5e, 0xe9, 0xb2, 0xcc, 0x10, 0xb2, 0x68, 0x19, 0x72, - 0xc9, 0xca, 0xb8, 0xfe, 0x92, 0x91, 0x8c, 0xf5, 0xf7, 0x63, 0xb5, 0x3d, 0xce, 0xbc, 0x09, 0xb5, - 0xfa, 0xef, 0x34, 0x28, 0x1c, 0xfa, 0xed, 0xd0, 0x22, 0x8f, 0x9b, 0x7c, 0x4b, 0x31, 0xf4, 0x1d, - 0x28, 0x74, 0x4e, 0xbe, 0x38, 0x83, 0x47, 0x66, 0x68, 0x42, 0xb8, 0x78, 0x54, 0xad, 0x4b, 0xda, - 0x61, 0x22, 0x5d, 0xb7, 0x79, 0xc0, 0x59, 0xd7, 0x18, 0xbd, 0x06, 0x33, 0xd8, 0xb6, 0x43, 0xc2, - 0x98, 0x58, 0xe5, 0x6c, 0xad, 0xf2, 0xb7, 0x3f, 0xbc, 0x5a, 0x56, 0x17, 0xc8, 0xba, 0xe4, 0x1c, - 0x46, 0x21, 0xf5, 0x5a, 0x3b, 0x53, 0x46, 0x3c, 0xb5, 0x96, 0x83, 0x2c, 0x13, 0x46, 0xea, 0xbf, - 0x4d, 0xc3, 0xad, 0xa3, 0x10, 0x7b, 0xac, 0x49, 0xc2, 0xd8, 0x0f, 0x2d, 0x28, 0x33, 0xe2, 0xd9, - 0x24, 0x34, 0x6f, 0xce, 0x70, 0x03, 0x49, 0xc8, 0x6e, 0x1a, 0x72, 0xe1, 0x4e, 0x48, 0x2c, 0x1a, - 0x50, 0xe2, 0x45, 0x7d, 0xba, 0x52, 0xd7, 0xd1, 0xb5, 0x90, 0xa0, 0xf6, 0xa8, 0x5b, 0x82, 0x1c, - 0x66, 0x4c, 0x1e, 0x23, 0x69, 0x91, 0x92, 0x33, 0x62, 0x5c, 0xb7, 0xd1, 0x22, 0x64, 0xb1, 0xcb, - 0xa7, 0x89, 0x9d, 0x98, 0x31, 0xd4, 0x08, 0xd5, 0x20, 0x2b, 0xed, 0xae, 0x4c, 0x0b, 0x83, 0x5e, - 0x1a, 0x9b, 0x14, 0x3d, 0x81, 0x37, 0x94, 0x24, 0xda, 0x81, 0xd9, 0xc4, 0x9e, 0x4a, 0xf6, 0x85, - 0x61, 0x3a, 0xc2, 0xfa, 0x47, 0x19, 0x28, 0x3e, 0x0e, 0x6d, 0x12, 0x6e, 0x53, 0xc7, 0x89, 0xa3, - 0x75, 0x0c, 0x79, 0x17, 0x9f, 0x93, 0xd0, 0xf4, 0x39, 0x67, 0x7c, 0xf2, 0x0e, 0x71, 0x9c, 0xc0, - 0x53, 0x17, 0x07, 0x08, 0x20, 0x41, 0x41, 0xdb, 0x30, 0x2d, 0x01, 0x53, 0x5f, 0x04, 0x70, 0x67, - 0xca, 0x90, 0xe2, 0xe8, 0x03, 0x28, 0x39, 0xf4, 0x69, 0x9b, 0xda, 0x38, 0xa2, 0xbe, 0xa7, 0x8c, - 0x94, 0xc7, 0xdd, 0xea, 0x58, 0x2f, 0xec, 0x75, 0xa4, 0x04, 0xa4, 0x38, 0xed, 0x8a, 0x4e, 0x1f, - 0x15, 0xdd, 0x83, 0x7c, 0x93, 0x3a, 0x8e, 0xa9, 0xc2, 0x97, 0x16, 0xe1, 0x03, 0x4e, 0x5a, 0x97, - 0x21, 0x14, 0xb7, 0x07, 0xf7, 0x4f, 0x93, 0x10, 0x11, 0x45, 0xc4, 0x6f, 0x8f, 0x73, 0x12, 0x6e, - 0x13, 0xc2, 0x99, 0x51, 0xc2, 0xcc, 0x4a, 0x66, 0x14, 0x33, 0x5f, 0x01, 0x14, 0xf9, 0x11, 0x76, - 0x4c, 0x8e, 0x46, 0x6c, 0x53, 0x48, 0x55, 0x66, 0x84, 0x86, 0xa2, 0xe0, 0x6c, 0x0b, 0xc6, 0x3e, - 0xa7, 0x0f, 0xcc, 0x16, 0x30, 0x95, 0xdc, 0xc0, 0xec, 0x23, 0x31, 0xbb, 0x0a, 0xb7, 0x71, 0xb3, - 0x49, 0x1d, 0x8a, 0x23, 0x62, 0x86, 0xe4, 0xc2, 0x14, 0xa5, 0x5b, 0x65, 0x56, 0x9e, 0xc1, 0x09, - 0xcb, 0x20, 0x17, 0x87, 0x9c, 0x51, 0x2b, 0x40, 0x3e, 0xea, 0x44, 0x59, 0xff, 0x71, 0x1a, 0x6e, - 0x6f, 0x12, 0x87, 0x5c, 0x90, 0x10, 0xb7, 0xba, 0xea, 0x87, 0x6f, 0x03, 0xc4, 0x1e, 0x22, 0xd7, - 0xdb, 0xb0, 0x71, 0x4a, 0x74, 0xe0, 0x38, 0xb8, 0xdf, 0x6c, 0x32, 0x12, 0x45, 0xd4, 0x6b, 0x5d, - 0x6b, 0x87, 0xc6, 0xe0, 0x1d, 0xb8, 0x81, 0x52, 0x2e, 0x3d, 0x58, 0xca, 0xf5, 0x85, 0x3a, 0x33, - 0x10, 0xea, 0x87, 0x50, 0x96, 0x21, 0x78, 0xda, 0xf6, 0x23, 0x62, 0x3e, 0x6d, 0x63, 0x2f, 0x6a, - 0xbb, 0x4c, 0x44, 0x3d, 0x63, 0xc8, 0xf0, 0xbc, 0xc3, 0x59, 0xef, 0x28, 0x0e, 0x5a, 0x80, 0x2c, - 0x65, 0xe6, 0x69, 0xfb, 0x52, 0x04, 0x3f, 0x67, 0x4c, 0x53, 0x56, 0x6b, 0x5f, 0xf2, 0xe8, 0x50, - 0x66, 0x36, 0xa9, 0x87, 0x1d, 0x93, 0x1b, 0xe8, 0x10, 0x97, 0x6f, 0xde, 0x19, 0x31, 0xa7, 0x44, - 0xd9, 0x36, 0xe7, 0x1c, 0x26, 0x0c, 0xfd, 0x47, 0x29, 0x40, 0x83, 0xf9, 0xfa, 0xe5, 0x46, 0xe3, - 0x3e, 0xcc, 0xf1, 0x82, 0xdd, 0xe4, 0x37, 0x6f, 0x7c, 0x62, 0x16, 0x0c, 0xe0, 0xb4, 0x06, 0xa6, - 0x61, 0xdd, 0x9e, 0xc4, 0xa5, 0x5f, 0x05, 0x90, 0x1e, 0x63, 0xf4, 0x39, 0x51, 0x1e, 0x9d, 0x15, - 0x94, 0x43, 0xfa, 0x9c, 0x74, 0xb9, 0x67, 0xba, 0xdb, 0x3d, 0xcb, 0x90, 0x63, 0xed, 0xd3, 0x88, - 0x5a, 0xe7, 0x4c, 0xf8, 0x2d, 0x63, 0x24, 0x63, 0xfd, 0xdf, 0x29, 0xb8, 0xd3, 0xb1, 0xbc, 0xb7, - 0xf0, 0x78, 0x72, 0x93, 0x57, 0x61, 0xdf, 0x45, 0xf8, 0x1c, 0x56, 0x64, 0x05, 0x68, 0x9b, 0x9d, - 0x45, 0x07, 0x3e, 0xa3, 0x3c, 0x20, 0xac, 0x92, 0x16, 0xd5, 0xf4, 0x5b, 0x13, 0x6b, 0x6a, 0xc4, - 0x18, 0x0d, 0x05, 0x61, 0x2c, 0x29, 0xf8, 0x01, 0x0e, 0x43, 0x1e, 0xdc, 0x89, 0x75, 0xcb, 0x0b, - 0xa6, 0xa3, 0x37, 0x23, 0xf4, 0xbe, 0x31, 0xb1, 0xde, 0x75, 0x2e, 0x9f, 0xe8, 0x5c, 0x50, 0xb0, - 0x3d, 0x54, 0xb6, 0x9b, 0xc9, 0xa5, 0x8a, 0x69, 0xfd, 0x9f, 0x73, 0x50, 0x3e, 0x8c, 0x70, 0x44, - 0x9a, 0x6d, 0x47, 0x64, 0x5c, 0xec, 0xe6, 0xa7, 0x90, 0x17, 0xa7, 0x84, 0x19, 0x38, 0xd8, 0x8a, - 0xcb, 0x99, 0xdd, 0xf1, 0x57, 0xce, 0x10, 0x9c, 0x5e, 0x62, 0x83, 0x63, 0xb9, 0x82, 0x51, 0x4b, - 0x55, 0xb4, 0x1d, 0xbe, 0x7b, 0x13, 0x3a, 0xf2, 0xa1, 0x20, 0x55, 0xaa, 0xa7, 0xa7, 0x3a, 0xe1, - 0x77, 0xae, 0xa9, 0xd4, 0x90, 0x68, 0xb2, 0xd0, 0xf5, 0xbb, 0x28, 0xe8, 0x27, 0x1a, 0xac, 0x58, - 0xbe, 0x67, 0x0b, 0x8f, 0x60, 0xc7, 0xec, 0x5a, 0xb0, 0xd8, 0xaa, 0xf2, 0xba, 0xde, 0x7f, 0x71, - 0xfd, 0x1b, 0x1d, 0xd0, 0xfe, 0x75, 0xef, 0x4c, 0x19, 0x4b, 0xd6, 0x28, 0xf6, 0x08, 0x8b, 0xa2, - 0x90, 0xb6, 0x5a, 0x24, 0x24, 0xb6, 0xba, 0xf9, 0x6f, 0xc0, 0xa2, 0xa3, 0x18, 0x72, 0xb8, 0x45, - 0x09, 0x1b, 0x7d, 0xa4, 0xc1, 0x92, 0xe3, 0x7b, 0x2d, 0x33, 0x22, 0xa1, 0x3b, 0xe0, 0xa1, 0x99, - 0x2f, 0x9a, 0x16, 0x7b, 0xbe, 0xd7, 0x3a, 0x22, 0xa1, 0x3b, 0xc4, 0x3d, 0x8b, 0xce, 0x50, 0x1e, - 0xfa, 0x1e, 0x94, 0xe2, 0xf4, 0xe8, 0x18, 0x90, 0x13, 0x06, 0xec, 0x5d, 0xd3, 0x00, 0xa3, 0x83, - 0x28, 0x2b, 0x04, 0xbf, 0x8f, 0xba, 0xfc, 0x5d, 0xa8, 0x8c, 0xca, 0x64, 0xb4, 0x19, 0x57, 0x39, - 0x5f, 0xa8, 0x6c, 0x52, 0x35, 0xce, 0xf2, 0x9f, 0x34, 0x58, 0x1c, 0x9e, 0xb7, 0xe8, 0x09, 0x14, - 0xc5, 0x96, 0x20, 0xb6, 0x0a, 0x40, 0x72, 0xea, 0x3d, 0x7c, 0x31, 0x5d, 0x75, 0xdb, 0x98, 0x57, - 0x48, 0x6a, 0x8c, 0xde, 0x86, 0xac, 0xec, 0xf0, 0xa8, 0x07, 0xfe, 0x88, 0x7a, 0x4a, 0x36, 0x85, - 0xaa, 0xdd, 0x86, 0x19, 0x42, 0xcc, 0x50, 0xe2, 0xcb, 0x16, 0xac, 0x8c, 0x49, 0xfb, 0x1b, 0x72, - 0xd2, 0xf7, 0x07, 0x95, 0x74, 0x65, 0x32, 0xfa, 0x00, 0x50, 0xb2, 0x57, 0xae, 0xef, 0xaa, 0x62, - 0x82, 0xa5, 0x28, 0x3c, 0x0b, 0x46, 0x25, 0xee, 0x0d, 0x2d, 0xf0, 0x8f, 0x1a, 0x2c, 0x8f, 0x4e, - 0x4d, 0x64, 0xc0, 0x9c, 0xef, 0xdc, 0xc0, 0xd2, 0xc0, 0x77, 0x92, 0x0c, 0xd8, 0xbc, 0x56, 0x91, - 0xae, 0x0c, 0x4f, 0x9a, 0x06, 0xf2, 0x5e, 0xd9, 0xcd, 0xe4, 0xd2, 0xc5, 0x8c, 0xfe, 0x6b, 0x0d, - 0x90, 0xb8, 0x76, 0x7a, 0x9f, 0xe6, 0xf3, 0x90, 0x4a, 0x9a, 0x30, 0x29, 0x2a, 0x1e, 0x4e, 0xec, - 0xd2, 0x3d, 0xf5, 0x1d, 0xf9, 0xfc, 0x34, 0xd4, 0x88, 0x17, 0x16, 0x67, 0x98, 0x99, 0xb2, 0x39, - 0x21, 0x2a, 0x8f, 0x9c, 0x31, 0x7b, 0x86, 0x99, 0x7c, 0x37, 0xf7, 0xb6, 0x74, 0x32, 0x7d, 0x2d, - 0x9d, 0x97, 0xa1, 0x84, 0x23, 0xdf, 0xa5, 0x96, 0x19, 0x12, 0xe6, 0x3b, 0x6d, 0x9e, 0x31, 0xe2, - 0x40, 0x2f, 0x19, 0x45, 0xc9, 0x30, 0x12, 0xba, 0xfe, 0xe7, 0x34, 0x7c, 0x25, 0xb9, 0x92, 0x87, - 0x35, 0x13, 0xfa, 0x2d, 0xbe, 0xba, 0x6e, 0x5a, 0x84, 0x2c, 0xaf, 0x65, 0x48, 0x28, 0xec, 0x9e, - 0x35, 0xd4, 0x68, 0xbc, 0xd1, 0x3b, 0x90, 0x65, 0x11, 0x8e, 0xda, 0xb2, 0xda, 0x9c, 0x9f, 0x24, - 0xb0, 0x1b, 0x4a, 0xe5, 0xa1, 0x90, 0x33, 0x94, 0x3c, 0xfa, 0x26, 0xac, 0xa8, 0xca, 0xd5, 0xb4, - 0x7c, 0xef, 0x82, 0x84, 0x8c, 0x3f, 0x9c, 0x92, 0x66, 0x46, 0x56, 0x38, 0x62, 0x49, 0x4d, 0xd9, - 0x48, 0x66, 0xc4, 0xed, 0x9a, 0xe1, 0xee, 0x9b, 0x19, 0xee, 0x3e, 0xf4, 0x12, 0x94, 0xe2, 0xd2, - 0x8d, 0xd7, 0x4d, 0x26, 0xff, 0x25, 0x4e, 0xe6, 0x82, 0x71, 0x2b, 0x66, 0x34, 0x48, 0x78, 0x44, - 0xad, 0x73, 0xfe, 0xc2, 0x61, 0x11, 0x09, 0xcc, 0x53, 0xcc, 0xba, 0x8a, 0x6b, 0xf9, 0x64, 0x29, - 0x72, 0x4e, 0x0d, 0xb3, 0x4e, 0x69, 0xfd, 0x75, 0x98, 0x97, 0xd5, 0x2a, 0x8d, 0x2e, 0xcd, 0x88, - 0x92, 0xb0, 0x02, 0x02, 0xb6, 0x90, 0x50, 0x8f, 0x28, 0x09, 0xdf, 0x4a, 0x55, 0x34, 0xfd, 0xe7, - 0x99, 0xb1, 0x31, 0x5c, 0xfb, 0x7f, 0x0c, 0xff, 0xab, 0x63, 0x88, 0x4e, 0x20, 0xaf, 0x9c, 0x2a, - 0xda, 0xcd, 0x79, 0xe1, 0xbc, 0x09, 0xaa, 0xfa, 0xbe, 0x98, 0x8b, 0x9e, 0x33, 0xb8, 0xc9, 0x6f, - 0xfd, 0x57, 0x29, 0x58, 0xde, 0xeb, 0xd6, 0x74, 0x1c, 0x30, 0x12, 0x46, 0xa3, 0x76, 0x36, 0x82, - 0x8c, 0x87, 0x5d, 0xa2, 0x4e, 0x22, 0xf1, 0x9b, 0xaf, 0x97, 0x7a, 0x34, 0xa2, 0xd8, 0xe1, 0x67, - 0x51, 0x8b, 0x7a, 0xa2, 0x21, 0x29, 0x5f, 0x42, 0x45, 0xc5, 0xd9, 0x17, 0x8c, 0x46, 0xe0, 0xa2, - 0x37, 0xa1, 0xe2, 0x62, 0xea, 0x45, 0xc4, 0xc3, 0x9e, 0x45, 0xcc, 0x66, 0x88, 0x2d, 0xd1, 0xb5, - 0xe0, 0x32, 0x32, 0x59, 0x16, 0xbb, 0xf8, 0xdb, 0x8a, 0x2d, 0x25, 0x17, 0x85, 0x4b, 0xe3, 0xca, - 0xdf, 0xf4, 0x7c, 0x79, 0xd1, 0xc9, 0xc7, 0x27, 0x2f, 0x99, 0x8d, 0x32, 0x9f, 0x11, 0x57, 0xf1, - 0x07, 0x8a, 0xbf, 0x9b, 0xc9, 0x65, 0x8b, 0x33, 0xbb, 0x99, 0xdc, 0x4c, 0x31, 0x67, 0xdc, 0xf1, - 0x03, 0xe2, 0x99, 0x5c, 0x41, 0x48, 0x58, 0x64, 0x3a, 0xfe, 0x33, 0x12, 0x9a, 0x16, 0x0e, 0xfa, - 0x19, 0xed, 0x20, 0x90, 0x0c, 0xfd, 0x97, 0x29, 0x58, 0x90, 0x8f, 0xac, 0x38, 0x13, 0x63, 0xef, - 0xf4, 0xef, 0x11, 0x6d, 0x60, 0x8f, 0x74, 0xd2, 0x3d, 0xf5, 0xe5, 0xa6, 0x7b, 0xfa, 0xaa, 0x74, - 0x1f, 0x9a, 0xc1, 0x99, 0x17, 0xc9, 0xe0, 0xe9, 0xe1, 0x19, 0xac, 0xff, 0x5e, 0x83, 0x45, 0xe9, - 0x9f, 0x24, 0xd9, 0xc6, 0x5c, 0x65, 0xea, 0xc8, 0x48, 0x8d, 0x3e, 0x32, 0xd2, 0x93, 0xdc, 0x55, - 0x99, 0x11, 0x1b, 0x75, 0x70, 0x3b, 0x4d, 0x0f, 0xd9, 0x4e, 0x3a, 0x83, 0x85, 0xa3, 0x10, 0xdb, - 0xd4, 0x6b, 0x19, 0xe4, 0x19, 0x0e, 0x6d, 0xd6, 0x79, 0x3f, 0xdf, 0x8a, 0x24, 0xc3, 0x0c, 0x25, - 0x47, 0x7d, 0x25, 0x7a, 0x34, 0xb6, 0x88, 0x56, 0x6d, 0xe0, 0x1e, 0x4c, 0x63, 0x3e, 0xea, 0x51, - 0xa1, 0xff, 0x42, 0x83, 0xf2, 0xb0, 0x89, 0xa8, 0x0c, 0xd3, 0xfe, 0x33, 0x8f, 0xc4, 0x9d, 0x7e, - 0x39, 0x40, 0xe7, 0x30, 0x67, 0x13, 0xcf, 0x77, 0xe3, 0x66, 0x4c, 0xea, 0x86, 0xbf, 0x94, 0xe5, - 0x05, 0xba, 0xec, 0xeb, 0xe8, 0x3f, 0xd0, 0x60, 0xe9, 0x71, 0x40, 0xbc, 0xba, 0xca, 0xff, 0xde, - 0xae, 0x82, 0x05, 0x0b, 0xfd, 0xbb, 0xa3, 0xfb, 0x0b, 0xda, 0xf8, 0x2e, 0xe3, 0x20, 0xac, 0x71, - 0xdb, 0x1f, 0xa0, 0x31, 0xfd, 0x37, 0x1a, 0xa0, 0xc1, 0xb9, 0x93, 0x7c, 0x80, 0x74, 0xa1, 0xd0, - 0x63, 0xde, 0x8d, 0xbb, 0x6a, 0xae, 0xdb, 0x5e, 0xfd, 0x93, 0x71, 0x67, 0xe6, 0xda, 0xff, 0xc6, - 0x99, 0x89, 0x5e, 0x87, 0x51, 0x27, 0xa5, 0xea, 0x47, 0x95, 0xbb, 0x7d, 0xb2, 0xc7, 0x99, 0x1b, - 0x38, 0x18, 0x14, 0x4b, 0xce, 0x51, 0xd5, 0xd5, 0x2d, 0xf7, 0x86, 0x3e, 0x10, 0x62, 0xfa, 0x0f, - 0x35, 0xa8, 0x18, 0xa4, 0x45, 0x59, 0x44, 0xc2, 0xf5, 0xb8, 0x33, 0x1b, 0x67, 0xdf, 0x1a, 0xcc, - 0x84, 0xa4, 0x49, 0x42, 0x22, 0x1b, 0x2d, 0x63, 0x3e, 0xc0, 0x18, 0xf1, 0x44, 0xf4, 0x06, 0xcc, - 0x26, 0x1d, 0xde, 0xab, 0x3e, 0xdb, 0x18, 0x9d, 0xa9, 0xfc, 0x30, 0x43, 0x32, 0x9c, 0x27, 0xb8, - 0xed, 0x44, 0x5d, 0x26, 0xc4, 0xdf, 0x80, 0xae, 0x34, 0x41, 0x4d, 0x9c, 0xa0, 0x82, 0xda, 0x4a, - 0x6e, 0x87, 0xb4, 0xb8, 0x1d, 0x5e, 0xbd, 0xfa, 0x76, 0x10, 0x56, 0xf5, 0x5e, 0x0d, 0x35, 0xe3, - 0xe3, 0xcf, 0xee, 0x6a, 0x9f, 0x7c, 0x76, 0x57, 0xfb, 0xd7, 0x67, 0x77, 0xb5, 0x9f, 0x7e, 0x7e, - 0x77, 0xea, 0x93, 0xcf, 0xef, 0x4e, 0xfd, 0xfd, 0xf3, 0xbb, 0x53, 0x4f, 0xde, 0x9c, 0x3c, 0xf3, - 0x7b, 0xff, 0xaf, 0xe2, 0x34, 0x2b, 0x18, 0xdf, 0xf8, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xac, - 0xfe, 0xc7, 0x4a, 0x7d, 0x21, 0x00, 0x00, + // 2441 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcd, 0x6f, 0x24, 0x47, + 0x15, 0x77, 0xcf, 0x8c, 0xc7, 0xe3, 0x37, 0x1e, 0xef, 0x4c, 0xed, 0xd8, 0x3b, 0xb6, 0x61, 0x77, + 0x69, 0x09, 0x69, 0x95, 0x8f, 0xf1, 0xae, 0x49, 0xa2, 0x28, 0x07, 0x84, 0xc7, 0x1f, 0xf1, 0x58, + 0xb6, 0x77, 0xd2, 0xfe, 0x48, 0xb2, 0xa0, 0x34, 0xe5, 0xee, 0x9a, 0x71, 0xc9, 0xfd, 0xb5, 0x5d, + 0x3d, 0xde, 0x78, 0x11, 0x37, 0x44, 0x38, 0x20, 0x81, 0x84, 0x38, 0x70, 0x40, 0xe2, 0xc2, 0x25, + 0x12, 0x07, 0x24, 0xc4, 0x8d, 0x03, 0xe2, 0x92, 0x1b, 0x11, 0x27, 0x04, 0x52, 0x84, 0x92, 0x03, + 0xff, 0x06, 0xaa, 0x8f, 0xee, 0xf9, 0x1e, 0xcf, 0xc6, 0x8e, 0x84, 0x10, 0x27, 0x4f, 0xbd, 0x57, + 0xef, 0xf7, 0x5e, 0xbd, 0xf7, 0xaa, 0xea, 0xd5, 0x6b, 0xc3, 0x03, 0xfb, 0xd2, 0xfe, 0x30, 0x08, + 0xfd, 0xc8, 0xb7, 0x7c, 0x67, 0x95, 0x7a, 0x36, 0xf9, 0x90, 0x84, 0xab, 0xe4, 0x82, 0x78, 0x11, + 0x53, 0x7f, 0xaa, 0x82, 0x8d, 0x56, 0xba, 0x67, 0x56, 0xd5, 0xcc, 0xaa, 0x9c, 0xb2, 0xbc, 0x64, + 0xf9, 0xcc, 0xf5, 0x99, 0x29, 0xf8, 0xab, 0x72, 0x20, 0xe5, 0x96, 0xcb, 0x2d, 0xbf, 0xe5, 0x4b, + 0x3a, 0xff, 0xa5, 0xa8, 0x0f, 0x87, 0xea, 0x65, 0x67, 0x38, 0x24, 0xf6, 0x6a, 0x48, 0x5c, 0xff, + 0x02, 0x3b, 0x66, 0x48, 0x30, 0xf3, 0x3d, 0x25, 0xf1, 0xf2, 0x50, 0x89, 0x84, 0x70, 0xf1, 0x68, + 0xd5, 0x72, 0xfc, 0xd3, 0xb1, 0xf0, 0xdd, 0x93, 0x03, 0x12, 0x06, 0x24, 0x6a, 0x63, 0x47, 0x49, + 0x3c, 0xba, 0x52, 0x82, 0xb5, 0x4f, 0xb1, 0x65, 0xf9, 0x6d, 0x2f, 0x52, 0x22, 0xaf, 0x5c, 0x29, + 0x72, 0x81, 0xdb, 0x8e, 0x9a, 0xad, 0xff, 0x55, 0x83, 0x5b, 0xdb, 0x6d, 0xcf, 0xa6, 0x5e, 0xeb, + 0x38, 0xb0, 0x71, 0x44, 0x4e, 0x1e, 0xa1, 0x6f, 0xc0, 0x5c, 0x62, 0x87, 0x49, 0xed, 0x8a, 0x76, + 0x5f, 0x7b, 0x50, 0x30, 0xf2, 0x09, 0xad, 0x6e, 0xa3, 0x97, 0xa0, 0xd4, 0x94, 0x52, 0xe6, 0x05, + 0x76, 0xda, 0xc4, 0x0c, 0x02, 0xb7, 0x92, 0xba, 0xaf, 0x3d, 0x98, 0x36, 0x6e, 0x29, 0xc6, 0x09, + 0xa7, 0x37, 0x02, 0x17, 0xb9, 0x50, 0x88, 0xe7, 0x0a, 0x6b, 0x2a, 0xe9, 0xfb, 0xda, 0x83, 0xb9, + 0xda, 0xce, 0x27, 0x9f, 0xdd, 0x9b, 0xfa, 0xc7, 0x67, 0xf7, 0xbe, 0xd3, 0xa2, 0xd1, 0x59, 0xfb, + 0xb4, 0x6a, 0xf9, 0xee, 0x6a, 0x8f, 0xe9, 0x17, 0xaf, 0xbd, 0x6a, 0x9d, 0x61, 0xea, 0x75, 0x6c, + 0xb7, 0xa3, 0xcb, 0x80, 0xb0, 0xea, 0x21, 0x09, 0x29, 0x76, 0xe8, 0x73, 0x7c, 0xea, 0x90, 0xba, + 0x17, 0x19, 0x73, 0x0a, 0xbe, 0xce, 0xd1, 0xf5, 0x5f, 0xa4, 0x60, 0x5e, 0xad, 0x68, 0x8b, 0xa7, + 0xc1, 0xc9, 0x23, 0xb4, 0x07, 0x33, 0x6d, 0xb1, 0x38, 0x56, 0xd1, 0xee, 0xa7, 0x1f, 0xe4, 0xd7, + 0x5e, 0xa9, 0x8e, 0x49, 0x9b, 0x6a, 0x9f, 0x3f, 0x6a, 0x19, 0x6e, 0xa9, 0x11, 0x43, 0xa0, 0x4d, + 0xc8, 0x70, 0x3b, 0xc4, 0x72, 0xe7, 0xd7, 0x1e, 0x4e, 0x02, 0xa5, 0x0c, 0xa9, 0x1e, 0x5d, 0x06, + 0xc4, 0x10, 0xd2, 0xba, 0x0b, 0x19, 0x3e, 0x42, 0x65, 0x28, 0x1e, 0xbd, 0xdf, 0xd8, 0x32, 0x8f, + 0x0f, 0x0e, 0x1b, 0x5b, 0x1b, 0xf5, 0xed, 0xfa, 0xd6, 0x66, 0x71, 0x0a, 0xdd, 0x81, 0xdb, 0x82, + 0xda, 0x30, 0xb6, 0xf6, 0xeb, 0xc7, 0xfb, 0xe6, 0xe1, 0xfa, 0x7e, 0x63, 0x6f, 0xab, 0xa8, 0xa1, + 0x7b, 0xb0, 0x22, 0x18, 0xdb, 0xc7, 0x07, 0x9b, 0xf5, 0x83, 0xb7, 0x4d, 0x63, 0xfd, 0x68, 0xcb, + 0x5c, 0x3f, 0xd8, 0x34, 0xeb, 0x07, 0x9b, 0x5b, 0xef, 0x15, 0x53, 0x68, 0x01, 0x4a, 0x3d, 0x92, + 0x27, 0x8f, 0x8f, 0xb6, 0x8a, 0x69, 0xfd, 0x2f, 0x29, 0x28, 0xec, 0xe3, 0xf0, 0x9c, 0x44, 0xb1, + 0x53, 0x56, 0x60, 0xd6, 0x15, 0x84, 0x4e, 0x88, 0x73, 0x92, 0x50, 0xb7, 0xd1, 0x13, 0x98, 0x0b, + 0x42, 0x6a, 0x11, 0x53, 0x2e, 0x5a, 0xac, 0x35, 0xbf, 0xf6, 0xfa, 0xd8, 0xb5, 0x4a, 0xf8, 0x06, + 0x17, 0x93, 0xae, 0x53, 0x9a, 0x76, 0xa6, 0x8c, 0x7c, 0xd0, 0xa1, 0xa2, 0x77, 0xa1, 0xa0, 0x14, + 0x5b, 0x21, 0xe1, 0xe0, 0x69, 0x01, 0xfe, 0x70, 0x02, 0xf0, 0x0d, 0x21, 0xd0, 0xc1, 0x9d, 0x73, + 0xbb, 0xc8, 0x5d, 0xc0, 0xae, 0x6f, 0xd3, 0xe6, 0x65, 0x25, 0x33, 0x31, 0xf0, 0xbe, 0x10, 0x18, + 0x00, 0x96, 0xe4, 0xda, 0x0c, 0x4c, 0x8b, 0xd9, 0xfa, 0x2e, 0x54, 0x46, 0xad, 0x12, 0x55, 0xe1, + 0xb6, 0x74, 0xd9, 0x33, 0x1a, 0x9d, 0x99, 0xe4, 0xc3, 0xc0, 0xf7, 0x88, 0x17, 0x09, 0xcf, 0x66, + 0x8c, 0x92, 0x60, 0xbd, 0x4b, 0xa3, 0xb3, 0x2d, 0xc5, 0xd0, 0xdf, 0x83, 0x92, 0xc4, 0xaa, 0x61, + 0x96, 0x80, 0x20, 0xc8, 0x04, 0x98, 0x86, 0x42, 0x6a, 0xd6, 0x10, 0xbf, 0xd1, 0x2a, 0x94, 0x5d, + 0xea, 0x99, 0x12, 0xdc, 0x3a, 0xc3, 0x5e, 0xab, 0xb3, 0xdd, 0x0a, 0x46, 0xc9, 0xa5, 0x9e, 0xb0, + 0x66, 0x43, 0x70, 0x1a, 0x81, 0xab, 0xb7, 0xe1, 0xf6, 0x10, 0x77, 0xa1, 0x1a, 0x64, 0x4e, 0x31, + 0x23, 0x02, 0x3b, 0xbf, 0x56, 0x9d, 0xc0, 0x2b, 0x5d, 0x96, 0x19, 0x42, 0x16, 0x2d, 0x43, 0x2e, + 0x59, 0x19, 0xd7, 0x5f, 0x32, 0x92, 0xb1, 0xfe, 0x7e, 0xac, 0xb6, 0xc7, 0x99, 0x37, 0xa1, 0x56, + 0xff, 0x9d, 0x06, 0x85, 0x43, 0xbf, 0x1d, 0x5a, 0xe4, 0x71, 0x93, 0x6f, 0x29, 0x86, 0xbe, 0x07, + 0x85, 0xce, 0xc9, 0x17, 0x67, 0xf0, 0xc8, 0x0c, 0x4d, 0x08, 0x17, 0x8f, 0xaa, 0x75, 0x49, 0x3b, + 0x4c, 0xa4, 0xeb, 0x36, 0x0f, 0x38, 0xeb, 0x1a, 0xa3, 0xd7, 0x60, 0x06, 0xdb, 0x76, 0x48, 0x18, + 0x13, 0xab, 0x9c, 0xad, 0x55, 0xfe, 0xf6, 0x87, 0x57, 0xcb, 0xea, 0x02, 0x59, 0x97, 0x9c, 0xc3, + 0x28, 0xa4, 0x5e, 0x6b, 0x67, 0xca, 0x88, 0xa7, 0xd6, 0x72, 0x90, 0x65, 0xc2, 0x48, 0xfd, 0xe3, + 0x34, 0xdc, 0x3a, 0x0a, 0xb1, 0xc7, 0x9a, 0x24, 0x8c, 0xfd, 0xd0, 0x82, 0x32, 0x23, 0x9e, 0x4d, + 0x42, 0xf3, 0xe6, 0x0c, 0x37, 0x90, 0x84, 0xec, 0xa6, 0x21, 0x17, 0xee, 0x84, 0xc4, 0xa2, 0x01, + 0x25, 0x5e, 0xd4, 0xa7, 0x2b, 0x75, 0x1d, 0x5d, 0x0b, 0x09, 0x6a, 0x8f, 0xba, 0x25, 0xc8, 0x61, + 0xc6, 0xe4, 0x31, 0x92, 0x16, 0x29, 0x39, 0x23, 0xc6, 0x75, 0x1b, 0x2d, 0x42, 0x16, 0xbb, 0x7c, + 0x9a, 0xd8, 0x89, 0x19, 0x43, 0x8d, 0x50, 0x0d, 0xb2, 0xd2, 0xee, 0xca, 0xb4, 0x30, 0xe8, 0xa5, + 0xb1, 0x49, 0xd1, 0x13, 0x78, 0x43, 0x49, 0xa2, 0x1d, 0x98, 0x4d, 0xec, 0xa9, 0x64, 0x5f, 0x18, + 0xa6, 0x23, 0xac, 0x7f, 0x94, 0x81, 0xe2, 0xe3, 0xd0, 0x26, 0xe1, 0x36, 0x75, 0x9c, 0x38, 0x5a, + 0xc7, 0x90, 0x77, 0xf1, 0x39, 0x09, 0x4d, 0x9f, 0x73, 0xc6, 0x27, 0xef, 0x10, 0xc7, 0x09, 0x3c, + 0x75, 0x71, 0x80, 0x00, 0x12, 0x14, 0xb4, 0x0d, 0xd3, 0x12, 0x30, 0xf5, 0x65, 0x00, 0x77, 0xa6, + 0x0c, 0x29, 0x8e, 0x3e, 0x80, 0x92, 0x43, 0x9f, 0xb6, 0xa9, 0x8d, 0x23, 0xea, 0x7b, 0xca, 0x48, + 0x79, 0xdc, 0xad, 0x8e, 0xf5, 0xc2, 0x5e, 0x47, 0x4a, 0x40, 0x8a, 0xd3, 0xae, 0xe8, 0xf4, 0x51, + 0xd1, 0x3d, 0xc8, 0x37, 0xa9, 0xe3, 0x98, 0x2a, 0x7c, 0x69, 0x11, 0x3e, 0xe0, 0xa4, 0x75, 0x19, + 0x42, 0x71, 0x7b, 0x70, 0xff, 0x34, 0x09, 0x11, 0x51, 0x44, 0xfc, 0xf6, 0x38, 0x27, 0xe1, 0x36, + 0x21, 0x9c, 0x19, 0x25, 0xcc, 0xac, 0x64, 0x46, 0x31, 0xf3, 0x15, 0x40, 0x91, 0x1f, 0x61, 0xc7, + 0xe4, 0x68, 0xc4, 0x36, 0x85, 0x54, 0x65, 0x46, 0x68, 0x28, 0x0a, 0xce, 0xb6, 0x60, 0xec, 0x73, + 0xfa, 0xc0, 0x6c, 0x01, 0x53, 0xc9, 0x0d, 0xcc, 0x3e, 0x12, 0xb3, 0xab, 0x70, 0x1b, 0x37, 0x9b, + 0xd4, 0xa1, 0x38, 0x22, 0x66, 0x48, 0x2e, 0x4c, 0x51, 0xba, 0x55, 0x66, 0xe5, 0x19, 0x9c, 0xb0, + 0x0c, 0x72, 0x71, 0xc8, 0x19, 0xb5, 0x02, 0xe4, 0xa3, 0x4e, 0x94, 0xf5, 0x9f, 0xa6, 0xe1, 0xf6, + 0x26, 0x71, 0xc8, 0x05, 0x09, 0x71, 0xab, 0xab, 0x7e, 0xf8, 0x2e, 0x40, 0xec, 0x21, 0x72, 0xbd, + 0x0d, 0x1b, 0xa7, 0x44, 0x07, 0x8e, 0x83, 0xfb, 0xcd, 0x26, 0x23, 0x51, 0x44, 0xbd, 0xd6, 0xb5, + 0x76, 0x68, 0x0c, 0xde, 0x81, 0x1b, 0x28, 0xe5, 0xd2, 0x83, 0xa5, 0x5c, 0x5f, 0xa8, 0x33, 0x03, + 0xa1, 0x7e, 0x08, 0x65, 0x19, 0x82, 0xa7, 0x6d, 0x3f, 0x22, 0xe6, 0xd3, 0x36, 0xf6, 0xa2, 0xb6, + 0xcb, 0x44, 0xd4, 0x33, 0x86, 0x0c, 0xcf, 0x3b, 0x9c, 0xf5, 0x8e, 0xe2, 0xa0, 0x05, 0xc8, 0x52, + 0x66, 0x9e, 0xb6, 0x2f, 0x45, 0xf0, 0x73, 0xc6, 0x34, 0x65, 0xb5, 0xf6, 0x25, 0x8f, 0x0e, 0x65, + 0x66, 0x93, 0x7a, 0xd8, 0x31, 0xb9, 0x81, 0x0e, 0x71, 0xf9, 0xe6, 0x9d, 0x11, 0x73, 0x4a, 0x94, + 0x6d, 0x73, 0xce, 0x61, 0xc2, 0xd0, 0x7f, 0x92, 0x02, 0x34, 0x98, 0xaf, 0x5f, 0x6d, 0x34, 0xee, + 0xc3, 0x1c, 0x2f, 0xd8, 0x4d, 0x7e, 0xf3, 0xc6, 0x27, 0x66, 0xc1, 0x00, 0x4e, 0x6b, 0x60, 0x1a, + 0xd6, 0xed, 0x49, 0x5c, 0xfa, 0x75, 0x00, 0xe9, 0x31, 0x46, 0x9f, 0x13, 0xe5, 0xd1, 0x59, 0x41, + 0x39, 0xa4, 0xcf, 0x49, 0x97, 0x7b, 0xa6, 0xbb, 0xdd, 0xb3, 0x0c, 0x39, 0xd6, 0x3e, 0x8d, 0xa8, + 0x75, 0xce, 0x84, 0xdf, 0x32, 0x46, 0x32, 0xd6, 0xff, 0x9d, 0x82, 0x3b, 0x1d, 0xcb, 0x7b, 0x0b, + 0x8f, 0x27, 0x37, 0x79, 0x15, 0xf6, 0x5d, 0x84, 0xcf, 0x61, 0x45, 0x56, 0x80, 0xb6, 0xd9, 0x59, + 0x74, 0xe0, 0x33, 0xca, 0x03, 0xc2, 0x2a, 0x69, 0x51, 0x4d, 0xbf, 0x35, 0xb1, 0xa6, 0x46, 0x8c, + 0xd1, 0x50, 0x10, 0xc6, 0x92, 0x82, 0x1f, 0xe0, 0x30, 0xe4, 0xc1, 0x9d, 0x58, 0xb7, 0xbc, 0x60, + 0x3a, 0x7a, 0x33, 0x42, 0xef, 0x1b, 0x13, 0xeb, 0x5d, 0xe7, 0xf2, 0x89, 0xce, 0x05, 0x05, 0xdb, + 0x43, 0x65, 0xbb, 0x99, 0x5c, 0xaa, 0x98, 0xd6, 0xff, 0x39, 0x07, 0xe5, 0xc3, 0x08, 0x47, 0xa4, + 0xd9, 0x76, 0x44, 0xc6, 0xc5, 0x6e, 0x7e, 0x0a, 0x79, 0x71, 0x4a, 0x98, 0x81, 0x83, 0xad, 0xb8, + 0x9c, 0xd9, 0x1d, 0x7f, 0xe5, 0x0c, 0xc1, 0xe9, 0x25, 0x36, 0x38, 0x96, 0x2b, 0x18, 0xb5, 0x54, + 0x45, 0xdb, 0xe1, 0xbb, 0x37, 0xa1, 0x23, 0x1f, 0x0a, 0x52, 0xa5, 0x7a, 0x7a, 0xaa, 0x13, 0x7e, + 0xe7, 0x9a, 0x4a, 0x0d, 0x89, 0x26, 0x0b, 0x5d, 0xbf, 0x8b, 0x82, 0x7e, 0xa6, 0xc1, 0x8a, 0xe5, + 0x7b, 0xb6, 0xf0, 0x08, 0x76, 0xcc, 0xae, 0x05, 0x8b, 0xad, 0x2a, 0xaf, 0xeb, 0xfd, 0x17, 0xd7, + 0xbf, 0xd1, 0x01, 0xed, 0x5f, 0xf7, 0xce, 0x94, 0xb1, 0x64, 0x8d, 0x62, 0x8f, 0xb0, 0x28, 0x0a, + 0x69, 0xab, 0x45, 0x42, 0x62, 0xab, 0x9b, 0xff, 0x06, 0x2c, 0x3a, 0x8a, 0x21, 0x87, 0x5b, 0x94, + 0xb0, 0xd1, 0x47, 0x1a, 0x2c, 0x39, 0xbe, 0xd7, 0x32, 0x23, 0x12, 0xba, 0x03, 0x1e, 0x9a, 0xf9, + 0xb2, 0x69, 0xb1, 0xe7, 0x7b, 0xad, 0x23, 0x12, 0xba, 0x43, 0xdc, 0xb3, 0xe8, 0x0c, 0xe5, 0xa1, + 0x1f, 0x40, 0x29, 0x4e, 0x8f, 0x8e, 0x01, 0x39, 0x61, 0xc0, 0xde, 0x35, 0x0d, 0x30, 0x3a, 0x88, + 0xb2, 0x42, 0xf0, 0xfb, 0xa8, 0xcb, 0xdf, 0x87, 0xca, 0xa8, 0x4c, 0x46, 0x9b, 0x71, 0x95, 0xf3, + 0xa5, 0xca, 0x26, 0x55, 0xe3, 0x2c, 0xff, 0x49, 0x83, 0xc5, 0xe1, 0x79, 0x8b, 0x9e, 0x40, 0x51, + 0x6c, 0x09, 0x62, 0xab, 0x00, 0x24, 0xa7, 0xde, 0xc3, 0x17, 0xd3, 0x55, 0xb7, 0x8d, 0x79, 0x85, + 0xa4, 0xc6, 0xe8, 0x6d, 0xc8, 0xca, 0x0e, 0x8f, 0x7a, 0xe0, 0x8f, 0xa8, 0xa7, 0x64, 0x53, 0xa8, + 0xda, 0x6d, 0x98, 0x21, 0xc4, 0x0c, 0x25, 0xbe, 0x6c, 0xc1, 0xca, 0x98, 0xb4, 0xbf, 0x21, 0x27, + 0xfd, 0x70, 0x50, 0x49, 0x57, 0x26, 0xa3, 0x0f, 0x00, 0x25, 0x7b, 0xe5, 0xfa, 0xae, 0x2a, 0x26, + 0x58, 0x8a, 0xc2, 0xb3, 0x60, 0x54, 0xe2, 0xde, 0xd0, 0x02, 0xff, 0xa8, 0xc1, 0xf2, 0xe8, 0xd4, + 0x44, 0x06, 0xcc, 0xf9, 0xce, 0x0d, 0x2c, 0x0d, 0x7c, 0x27, 0xc9, 0x80, 0xcd, 0x6b, 0x15, 0xe9, + 0xca, 0xf0, 0xa4, 0x69, 0x20, 0xef, 0x95, 0xdd, 0x4c, 0x2e, 0x5d, 0xcc, 0xe8, 0xbf, 0xd5, 0x00, + 0x89, 0x6b, 0xa7, 0xf7, 0x69, 0x3e, 0x0f, 0xa9, 0xa4, 0x09, 0x93, 0xa2, 0xe2, 0xe1, 0xc4, 0x2e, + 0xdd, 0x53, 0xdf, 0x91, 0xcf, 0x4f, 0x43, 0x8d, 0x78, 0x61, 0x71, 0x86, 0x99, 0x29, 0x9b, 0x13, + 0xa2, 0xf2, 0xc8, 0x19, 0xb3, 0x67, 0x98, 0xc9, 0x77, 0x73, 0x6f, 0x4b, 0x27, 0xd3, 0xd7, 0xd2, + 0x79, 0x19, 0x4a, 0x38, 0xf2, 0x5d, 0x6a, 0x99, 0x21, 0x61, 0xbe, 0xd3, 0xe6, 0x19, 0x23, 0x0e, + 0xf4, 0x92, 0x51, 0x94, 0x0c, 0x23, 0xa1, 0xeb, 0x7f, 0x4e, 0xc3, 0xd7, 0x92, 0x2b, 0x79, 0x58, + 0x33, 0xa1, 0xdf, 0xe2, 0xab, 0xeb, 0xa6, 0x45, 0xc8, 0xf2, 0x5a, 0x86, 0x84, 0xc2, 0xee, 0x59, + 0x43, 0x8d, 0xc6, 0x1b, 0xbd, 0x03, 0x59, 0x16, 0xe1, 0xa8, 0x2d, 0xab, 0xcd, 0xf9, 0x49, 0x02, + 0xbb, 0xa1, 0x54, 0x1e, 0x0a, 0x39, 0x43, 0xc9, 0xa3, 0x6f, 0xc3, 0x8a, 0xaa, 0x5c, 0x4d, 0xcb, + 0xf7, 0x2e, 0x48, 0xc8, 0xf8, 0xc3, 0x29, 0x69, 0x66, 0x64, 0x85, 0x23, 0x96, 0xd4, 0x94, 0x8d, + 0x64, 0x46, 0xdc, 0xae, 0x19, 0xee, 0xbe, 0x99, 0xe1, 0xee, 0x43, 0x2f, 0x41, 0x29, 0x2e, 0xdd, + 0x78, 0xdd, 0x64, 0xf2, 0x5f, 0xe2, 0x64, 0x2e, 0x18, 0xb7, 0x62, 0x46, 0x83, 0x84, 0x47, 0xd4, + 0x3a, 0xe7, 0x2f, 0x1c, 0x16, 0x91, 0xc0, 0x3c, 0xc5, 0xac, 0xab, 0xb8, 0x96, 0x4f, 0x96, 0x22, + 0xe7, 0xd4, 0x30, 0xeb, 0x94, 0xd6, 0xdf, 0x84, 0x79, 0x59, 0xad, 0xd2, 0xe8, 0xd2, 0x8c, 0x28, + 0x09, 0x2b, 0x20, 0x60, 0x0b, 0x09, 0xf5, 0x88, 0x92, 0xf0, 0xad, 0x54, 0x45, 0xd3, 0x7f, 0x99, + 0x19, 0x1b, 0xc3, 0xb5, 0xff, 0xc7, 0xf0, 0xbf, 0x3a, 0x86, 0xe8, 0x04, 0xf2, 0xca, 0xa9, 0xa2, + 0xdd, 0x9c, 0x17, 0xce, 0x9b, 0xa0, 0xaa, 0xef, 0x8b, 0xb9, 0xe8, 0x39, 0x83, 0x9b, 0xfc, 0xd6, + 0x7f, 0x93, 0x82, 0xe5, 0xbd, 0x6e, 0x4d, 0xc7, 0x01, 0x23, 0x61, 0x34, 0x6a, 0x67, 0x23, 0xc8, + 0x78, 0xd8, 0x25, 0xea, 0x24, 0x12, 0xbf, 0xf9, 0x7a, 0xa9, 0x47, 0x23, 0x8a, 0x1d, 0x7e, 0x16, + 0xb5, 0xa8, 0x27, 0x1a, 0x92, 0xf2, 0x25, 0x54, 0x54, 0x9c, 0x7d, 0xc1, 0x68, 0x04, 0x2e, 0x7a, + 0x13, 0x2a, 0x2e, 0xa6, 0x5e, 0x44, 0x3c, 0xec, 0x59, 0xc4, 0x6c, 0x86, 0xd8, 0x12, 0x5d, 0x0b, + 0x2e, 0x23, 0x93, 0x65, 0xb1, 0x8b, 0xbf, 0xad, 0xd8, 0x52, 0x72, 0x51, 0xb8, 0x34, 0xae, 0xfc, + 0x4d, 0xcf, 0x97, 0x17, 0x9d, 0x7c, 0x7c, 0xf2, 0x92, 0xd9, 0x28, 0xf3, 0x19, 0x71, 0x15, 0x7f, + 0xa0, 0xf8, 0xbb, 0x99, 0x5c, 0xb6, 0x38, 0xb3, 0x9b, 0xc9, 0xcd, 0x14, 0x73, 0xc6, 0x1d, 0x3f, + 0x20, 0x9e, 0xc9, 0x15, 0x84, 0x84, 0x45, 0xa6, 0xe3, 0x3f, 0x23, 0xa1, 0x69, 0xe1, 0xa0, 0x9f, + 0xd1, 0x0e, 0x02, 0xc9, 0xd0, 0x7f, 0x9d, 0x82, 0x05, 0xf9, 0xc8, 0x8a, 0x33, 0x31, 0xf6, 0x4e, + 0xff, 0x1e, 0xd1, 0x06, 0xf6, 0x48, 0x27, 0xdd, 0x53, 0x5f, 0x6d, 0xba, 0xa7, 0xaf, 0x4a, 0xf7, + 0xa1, 0x19, 0x9c, 0x79, 0x91, 0x0c, 0x9e, 0x1e, 0x9e, 0xc1, 0xfa, 0xef, 0x35, 0x58, 0x94, 0xfe, + 0x49, 0x92, 0x6d, 0xcc, 0x55, 0xa6, 0x8e, 0x8c, 0xd4, 0xe8, 0x23, 0x23, 0x3d, 0xc9, 0x5d, 0x95, + 0x19, 0xb1, 0x51, 0x07, 0xb7, 0xd3, 0xf4, 0x90, 0xed, 0xa4, 0x33, 0x58, 0x38, 0x0a, 0xb1, 0x4d, + 0xbd, 0x96, 0x41, 0x9e, 0xe1, 0xd0, 0x66, 0x9d, 0xf7, 0xf3, 0xad, 0x48, 0x32, 0xcc, 0x50, 0x72, + 0xd4, 0x57, 0xa2, 0x47, 0x63, 0x8b, 0x68, 0xd5, 0x06, 0xee, 0xc1, 0x34, 0xe6, 0xa3, 0x1e, 0x15, + 0xfa, 0xaf, 0x34, 0x28, 0x0f, 0x9b, 0x88, 0xca, 0x30, 0xed, 0x3f, 0xf3, 0x48, 0xdc, 0xe9, 0x97, + 0x03, 0x74, 0x0e, 0x73, 0x36, 0xf1, 0x7c, 0x37, 0x6e, 0xc6, 0xa4, 0x6e, 0xf8, 0x4b, 0x59, 0x5e, + 0xa0, 0xcb, 0xbe, 0x8e, 0xfe, 0x23, 0x0d, 0x96, 0x1e, 0x07, 0xc4, 0xab, 0xab, 0xfc, 0xef, 0xed, + 0x2a, 0x58, 0xb0, 0xd0, 0xbf, 0x3b, 0xba, 0xbf, 0xa0, 0x8d, 0xef, 0x32, 0x0e, 0xc2, 0x1a, 0xb7, + 0xfd, 0x01, 0x1a, 0x13, 0xd7, 0xd4, 0xc7, 0x1a, 0xa0, 0xc1, 0xf9, 0x93, 0x7c, 0x84, 0x74, 0xa1, + 0xd0, 0x63, 0xe2, 0x8d, 0xbb, 0x6b, 0xae, 0xdb, 0x66, 0x61, 0xec, 0xa7, 0xe3, 0xce, 0xce, 0xb5, + 0xff, 0x8d, 0xb3, 0x13, 0xbd, 0x0e, 0xa3, 0x4e, 0x4c, 0xd5, 0x97, 0x2a, 0x77, 0xfb, 0x65, 0x8f, + 0x33, 0x37, 0x70, 0x30, 0x28, 0x96, 0x9c, 0xa7, 0xaa, 0xbb, 0x5b, 0xee, 0x4d, 0x81, 0x40, 0x88, + 0xe9, 0x3f, 0xd6, 0xa0, 0x62, 0x90, 0x16, 0x65, 0x11, 0x09, 0xd7, 0xe3, 0x0e, 0x6d, 0x9c, 0x85, + 0x6b, 0x30, 0x13, 0x92, 0x26, 0x09, 0x89, 0x6c, 0xb8, 0x8c, 0xf9, 0x10, 0x63, 0xc4, 0x13, 0xd1, + 0x1b, 0x30, 0x9b, 0x74, 0x7a, 0xaf, 0xfa, 0x7c, 0x63, 0x74, 0xa6, 0xf2, 0x43, 0x0d, 0xc9, 0x70, + 0x9e, 0xe0, 0xb6, 0x13, 0x75, 0x99, 0x10, 0x7f, 0x0b, 0xba, 0xd2, 0x04, 0x35, 0x71, 0x82, 0x4a, + 0x6a, 0x2b, 0xb9, 0x25, 0xd2, 0xe2, 0x96, 0x78, 0xf5, 0xea, 0x5b, 0x42, 0x58, 0xd5, 0x7b, 0x45, + 0xd4, 0x8c, 0x4f, 0x3e, 0xbf, 0xab, 0x7d, 0xfa, 0xf9, 0x5d, 0xed, 0x5f, 0x9f, 0xdf, 0xd5, 0x7e, + 0xfe, 0xc5, 0xdd, 0xa9, 0x4f, 0xbf, 0xb8, 0x3b, 0xf5, 0xf7, 0x2f, 0xee, 0x4e, 0x3d, 0x79, 0x73, + 0xf2, 0xec, 0xef, 0xfd, 0xff, 0x8a, 0xd3, 0xac, 0x60, 0x7c, 0xeb, 0x3f, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x35, 0x4a, 0x0d, 0x23, 0x85, 0x21, 0x00, 0x00, } func (m *FundingUpdateV1) Marshal() (dAtA []byte, err error) { diff --git a/protocol/x/clob/e2e/long_term_orders_test.go b/protocol/x/clob/e2e/long_term_orders_test.go index af1dfde636..dc393bf5a0 100644 --- a/protocol/x/clob/e2e/long_term_orders_test.go +++ b/protocol/x/clob/e2e/long_term_orders_test.go @@ -825,22 +825,6 @@ func TestPlaceLongTermOrder(t *testing.T) { EventIndex: 2, Version: indexerevents.OrderFillEventVersion, }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewInt(10_000_000_000), - }, - }, - }), - }, }, TxHashes: []string{ string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ @@ -1169,22 +1153,6 @@ func TestPlaceLongTermOrder(t *testing.T) { EventIndex: 2, Version: indexerevents.OrderFillEventVersion, }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewInt(10_000_000_000), - }, - }, - }), - }, }, TxHashes: []string{ string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ @@ -1340,22 +1308,6 @@ func TestPlaceLongTermOrder(t *testing.T) { EventIndex: 2, Version: indexerevents.OrderFillEventVersion, }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewInt(20_000_000_000), - }, - }, - }), - }, }, TxHashes: []string{ string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ @@ -1739,22 +1691,6 @@ func TestRegression_InvalidTimeInForce(t *testing.T) { EventIndex: 2, Version: indexerevents.OrderFillEventVersion, }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewInt(10_000_000_000), - }, - }, - }), - }, }, TxHashes: []string{ string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ diff --git a/protocol/x/clob/e2e/short_term_orders_test.go b/protocol/x/clob/e2e/short_term_orders_test.go index 0312034c76..a6e7365ad0 100644 --- a/protocol/x/clob/e2e/short_term_orders_test.go +++ b/protocol/x/clob/e2e/short_term_orders_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/slices" - "github.com/dydxprotocol/v4-chain/protocol/dtypes" "github.com/dydxprotocol/v4-chain/protocol/indexer" indexerevents "github.com/dydxprotocol/v4-chain/protocol/indexer/events" "github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager" @@ -219,24 +218,6 @@ func TestPlaceOrder(t *testing.T) { ), ), }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewIntFromUint64( - PlaceOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20.Order.GetBigQuantums().Uint64(), - ), - }, - }, - }), - }, }, TxHashes: []string{string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ OperationsQueue: []clobtypes.OperationRaw{ @@ -399,24 +380,6 @@ func TestPlaceOrder(t *testing.T) { ), ), }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewIntFromUint64( - PlaceOrder_Bob_Num0_Id0_Clob0_Sell5_Price10_GTB20.Order.GetBigQuantums().Uint64(), - ), - }, - }, - }), - }, }, TxHashes: []string{string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ OperationsQueue: []clobtypes.OperationRaw{ @@ -579,24 +542,6 @@ func TestPlaceOrder(t *testing.T) { ), ), }, - { - Subtype: indexerevents.SubtypeOpenInterestUpdate, - OrderingWithinBlock: &indexer_manager.IndexerTendermintEvent_BlockEvent_{ - BlockEvent: indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - }, - Version: indexerevents.OpenInterestUpdateVersion, - DataBytes: indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: []*indexerevents.OpenInterestUpdate{ - { - PerpetualId: Clob_0.MustGetPerpetualId(), - OpenInterest: dtypes.NewIntFromUint64( - PlaceOrder_Bob_Num0_Id0_Clob0_Sell5_Price10_GTB20.Order.GetBigQuantums().Uint64(), - ), - }, - }, - }), - }, }, TxHashes: []string{string(lib.GetTxHash(testtx.MustGetTxBytes(&clobtypes.MsgProposedOperations{ OperationsQueue: []clobtypes.OperationRaw{ diff --git a/protocol/x/perpetuals/abci.go b/protocol/x/perpetuals/abci.go index e8149df9a9..57a34f9e0c 100644 --- a/protocol/x/perpetuals/abci.go +++ b/protocol/x/perpetuals/abci.go @@ -15,5 +15,4 @@ func EndBlocker(ctx sdk.Context, k types.PerpetualsKeeper) { // first so that new samples are processed in `MaybeProcessNewFundingTickEpoch`. k.MaybeProcessNewFundingSampleEpoch(ctx) k.MaybeProcessNewFundingTickEpoch(ctx) - k.SendOIUpdatesToIndexer(ctx) } diff --git a/protocol/x/perpetuals/abci_test.go b/protocol/x/perpetuals/abci_test.go index e50a03080f..04ed81320f 100644 --- a/protocol/x/perpetuals/abci_test.go +++ b/protocol/x/perpetuals/abci_test.go @@ -28,10 +28,6 @@ func TestEndBlocker(t *testing.T) { "MaybeProcessNewFundingSampleEpoch", ctx, ).Return(nil) - mck.On( - "SendOIUpdatesToIndexer", - ctx, - ) }, expectedErr: nil, }, diff --git a/protocol/x/perpetuals/keeper/perpetual.go b/protocol/x/perpetuals/keeper/perpetual.go index c288f17982..834f67e96a 100644 --- a/protocol/x/perpetuals/keeper/perpetual.go +++ b/protocol/x/perpetuals/keeper/perpetual.go @@ -1,7 +1,6 @@ package keeper import ( - "encoding/binary" "fmt" "math/big" "math/rand" @@ -1041,14 +1040,6 @@ func (k Keeper) ModifyOpenInterest( perpetual.OpenInterest = dtypes.NewIntFromBigInt(bigOpenInterest) k.setPerpetual(ctx, perpetual) - if ctx.ExecMode() == sdk.ExecModeFinalize { - updatedOIStore := prefix.NewStore(ctx.TransientStore(k.transientStoreKey), []byte(types.UpdatedOIKeyPrefix)) - openInterestInBytes, err := perpetual.OpenInterest.Marshal() - if err != nil { - return err - } - updatedOIStore.Set(lib.Uint32ToKey(perpetualId), openInterestInBytes) - } return nil } @@ -1481,42 +1472,6 @@ func (k Keeper) IsPositionUpdatable( return true, nil } -func (k Keeper) SendOIUpdatesToIndexer(ctx sdk.Context) { - updatedOIStore := prefix.NewStore(ctx.TransientStore(k.transientStoreKey), []byte(types.UpdatedOIKeyPrefix)) - iterator := updatedOIStore.Iterator(nil, nil) - defer iterator.Close() - - OIMessageArray := make([]*indexerevents.OpenInterestUpdate, 0) - - for ; iterator.Valid(); iterator.Next() { - openInterestSerializableInt := dtypes.SerializableInt{} - if err := openInterestSerializableInt.Unmarshal(iterator.Value()); err != nil { - panic(errorsmod.Wrap(err, "failed to unmarshal open interest")) - } - OIMessage := indexerevents.OpenInterestUpdate{ - PerpetualId: binary.BigEndian.Uint32(iterator.Key()), - OpenInterest: openInterestSerializableInt, - } - OIMessageArray = append(OIMessageArray, &OIMessage) - } - - if len(OIMessageArray) == 0 { - return - } - - k.GetIndexerEventManager().AddBlockEvent( - ctx, - indexerevents.SubtypeOpenInterestUpdate, - indexer_manager.IndexerTendermintEvent_BLOCK_EVENT_END_BLOCK, - indexerevents.OpenInterestUpdateVersion, - indexer_manager.GetBytes( - &indexerevents.OpenInterestUpdateEventV1{ - OpenInterestUpdates: OIMessageArray, - }, - ), - ) -} - // GetNextPerpetualID returns the next perpetual id to be used from the module store func (k Keeper) GetNextPerpetualID(ctx sdk.Context) uint32 { store := ctx.KVStore(k.storeKey) diff --git a/protocol/x/perpetuals/keeper/perpetual_test.go b/protocol/x/perpetuals/keeper/perpetual_test.go index e3859b83e4..30cce2fa32 100644 --- a/protocol/x/perpetuals/keeper/perpetual_test.go +++ b/protocol/x/perpetuals/keeper/perpetual_test.go @@ -3013,32 +3013,6 @@ func TestIsPositionUpdatable(t *testing.T) { } } -func TestModifyOpenInterest_store(t *testing.T) { - pc := keepertest.PerpetualsKeepers(t) - perps := keepertest.CreateLiquidityTiersAndNPerpetuals(t, pc.Ctx, pc.PerpetualsKeeper, pc.PricesKeeper, 100) - pc.Ctx = pc.Ctx.WithExecMode(sdk.ExecModeFinalize) - for _, perp := range perps { - openInterestDeltaBaseQuantums := big.NewInt(2_000_000 * (int64(perp.Params.Id))) - - err := pc.PerpetualsKeeper.ModifyOpenInterest( - pc.Ctx, - perp.Params.Id, - openInterestDeltaBaseQuantums, - ) - require.NoError(t, err) - } - - transientStore := prefix.NewStore(pc.Ctx.TransientStore(pc.TransientStoreKey), []byte(types.UpdatedOIKeyPrefix)) - for _, perp := range perps { - perpetualObject, err := pc.PerpetualsKeeper.GetPerpetual(pc.Ctx, perp.Params.Id) - require.NoError(t, err) - serializedOpenInterest := dtypes.SerializableInt{} - err = serializedOpenInterest.Unmarshal(transientStore.Get(lib.Uint32ToKey(perpetualObject.Params.Id))) - require.NoError(t, err) - require.Equal(t, perpetualObject.OpenInterest, serializedOpenInterest) - } -} - func TestIsIsolatedPerpetual(t *testing.T) { testCases := map[string]struct { perp types.Perpetual diff --git a/protocol/x/perpetuals/types/types.go b/protocol/x/perpetuals/types/types.go index 0da2437d97..7268ec81a9 100644 --- a/protocol/x/perpetuals/types/types.go +++ b/protocol/x/perpetuals/types/types.go @@ -114,7 +114,6 @@ type PerpetualsKeeper interface { ctx sdk.Context, ) []Perpetual GetAllLiquidityTiers(ctx sdk.Context) (list []LiquidityTier) - SendOIUpdatesToIndexer(ctx sdk.Context) ValidateAndSetPerpetual( ctx sdk.Context, perpetual Perpetual, From 7c4036827958672a0351cba3eee2fa37e7b7d39c Mon Sep 17 00:00:00 2001 From: Tian Date: Wed, 16 Oct 2024 11:46:17 -0600 Subject: [PATCH 087/120] set each megavault share to be worth 0.001 usdc on 7.x upgrade (#2492) --- protocol/app/upgrades/v7.0.0/upgrade.go | 4 ++-- .../upgrades/v7.0.0/upgrade_container_test.go | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/app/upgrades/v7.0.0/upgrade.go b/protocol/app/upgrades/v7.0.0/upgrade.go index e0543670b9..dbf8f5644c 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade.go +++ b/protocol/app/upgrades/v7.0.0/upgrade.go @@ -21,8 +21,8 @@ import ( ) const ( - // Each megavault share is worth 1 USDC. - QUOTE_QUANTUMS_PER_MEGAVAULT_SHARE = 1_000_000 + // Each megavault share is worth 0.001 USDC. + QUOTE_QUANTUMS_PER_MEGAVAULT_SHARE = 1_000 ) var ( diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go index e2fa3ec9a3..069c647b19 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0.0/upgrade_container_test.go @@ -115,21 +115,21 @@ func checkVaultParams( func postUpgradeMegavaultSharesCheck(node *containertest.Node, t *testing.T) { // Alice equity = vault_0_equity * 1 + vault_1_equity * 1/3 + vault_2_equity * 123_456/556_677 // = 1_000 + 2_000 * 1/3 + 3_000 * 123_456/556_677 - // ~= 2331.99 + // ~= 2331.98605 // Bob equity = vault_1_equity * 1/3 + vault_2_equity * 433_221/556_677 // = 2_000 * 1/3 + 3_000 * 433_221/556_677 - // ~= 3001.35 + // ~= 3001.34728 // Carl equity = vault_1_equity * 1/3 // = 2_000 * 1/3 - // ~= 666.67 - // 1 USDC in equity should be granted 1 megavault share and round down to nearest integer. + // ~= 666.66667 + // 0.001 USDC in equity should be granted 1 megavault share and round down to nearest integer. expectedOwnerShares := map[string]*big.Int{ - constants.AliceAccAddress.String(): big.NewInt(2_331), - constants.BobAccAddress.String(): big.NewInt(3_001), - constants.CarlAccAddress.String(): big.NewInt(666), + constants.AliceAccAddress.String(): big.NewInt(2_331_986), + constants.BobAccAddress.String(): big.NewInt(3_001_347), + constants.CarlAccAddress.String(): big.NewInt(666_666), } - // 2331 + 3001 + 666 = 5998 - expectedTotalShares := big.NewInt(5_998) + // 2_331_986 + 3_001_347 + 666_666 = 5_999_999 + expectedTotalShares := big.NewInt(5_999_999) // Check MegaVault total shares. resp, err := containertest.Query( From 3db9b392b8b8a5ebf504c6b72fb201c11a44e9c5 Mon Sep 17 00:00:00 2001 From: Tian Date: Wed, 16 Oct 2024 16:25:51 -0600 Subject: [PATCH 088/120] add metadata to megavault operator params (#2509) --- .../src/codegen/dydxprotocol/vault/params.ts | 93 ++++- proto/dydxprotocol/vault/params.proto | 11 + .../app/testdata/default_genesis_state.json | 6 +- .../scripts/genesis/sample_pregenesis.json | 4 + protocol/testing/genesis.sh | 2 + protocol/testutil/constants/genesis.go | 6 +- protocol/x/vault/keeper/grpc_query_test.go | 1 + protocol/x/vault/keeper/params_test.go | 5 + protocol/x/vault/types/params.go | 4 + protocol/x/vault/types/params.pb.go | 353 ++++++++++++++++-- 10 files changed, 447 insertions(+), 38 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/params.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/params.ts index 85118c1e48..2d3e279da0 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/params.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/params.ts @@ -94,12 +94,38 @@ export interface VaultParamsSDKType { /** OperatorParams stores parameters regarding megavault operator. */ export interface OperatorParams { + /** Address of the operator. */ operator: string; + /** Metadata of the operator. */ + + metadata?: OperatorMetadata; } /** OperatorParams stores parameters regarding megavault operator. */ export interface OperatorParamsSDKType { + /** Address of the operator. */ operator: string; + /** Metadata of the operator. */ + + metadata?: OperatorMetadataSDKType; +} +/** OperatorMetadata stores metadata regarding megavault operator. */ + +export interface OperatorMetadata { + /** Name of the operator. */ + name: string; + /** Description of the operator. */ + + description: string; +} +/** OperatorMetadata stores metadata regarding megavault operator. */ + +export interface OperatorMetadataSDKType { + /** Name of the operator. */ + name: string; + /** Description of the operator. */ + + description: string; } /** * Deprecated: Params stores `x/vault` parameters. @@ -342,7 +368,8 @@ export const VaultParams = { function createBaseOperatorParams(): OperatorParams { return { - operator: "" + operator: "", + metadata: undefined }; } @@ -352,6 +379,10 @@ export const OperatorParams = { writer.uint32(10).string(message.operator); } + if (message.metadata !== undefined) { + OperatorMetadata.encode(message.metadata, writer.uint32(18).fork()).ldelim(); + } + return writer; }, @@ -368,6 +399,10 @@ export const OperatorParams = { message.operator = reader.string(); break; + case 2: + message.metadata = OperatorMetadata.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -380,6 +415,62 @@ export const OperatorParams = { fromPartial(object: DeepPartial): OperatorParams { const message = createBaseOperatorParams(); message.operator = object.operator ?? ""; + message.metadata = object.metadata !== undefined && object.metadata !== null ? OperatorMetadata.fromPartial(object.metadata) : undefined; + return message; + } + +}; + +function createBaseOperatorMetadata(): OperatorMetadata { + return { + name: "", + description: "" + }; +} + +export const OperatorMetadata = { + encode(message: OperatorMetadata, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.name !== "") { + writer.uint32(10).string(message.name); + } + + if (message.description !== "") { + writer.uint32(18).string(message.description); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OperatorMetadata { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOperatorMetadata(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.name = reader.string(); + break; + + case 2: + message.description = reader.string(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): OperatorMetadata { + const message = createBaseOperatorMetadata(); + message.name = object.name ?? ""; + message.description = object.description ?? ""; return message; } diff --git a/proto/dydxprotocol/vault/params.proto b/proto/dydxprotocol/vault/params.proto index f0f16fb714..002cc98b3e 100644 --- a/proto/dydxprotocol/vault/params.proto +++ b/proto/dydxprotocol/vault/params.proto @@ -51,7 +51,18 @@ message VaultParams { // OperatorParams stores parameters regarding megavault operator. message OperatorParams { + // Address of the operator. string operator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Metadata of the operator. + OperatorMetadata metadata = 2 [ (gogoproto.nullable) = false ]; +} + +// OperatorMetadata stores metadata regarding megavault operator. +message OperatorMetadata { + // Name of the operator. + string name = 1; + // Description of the operator. + string description = 2; } // Deprecated: Params stores `x/vault` parameters. diff --git a/protocol/app/testdata/default_genesis_state.json b/protocol/app/testdata/default_genesis_state.json index 0263da539b..598d1dbc98 100644 --- a/protocol/app/testdata/default_genesis_state.json +++ b/protocol/app/testdata/default_genesis_state.json @@ -528,7 +528,11 @@ "activation_threshold_quote_quantums": "1000000000" }, "operator_params": { - "operator": "dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky" + "operator": "dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky", + "metadata": { + "name": "Governance", + "description": "Governance Module Account" + } }, "owner_shares": [], "total_shares": { diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index 21ebb6f93d..b909f9ffc9 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -3972,6 +3972,10 @@ "spread_min_ppm": 3000 }, "operator_params": { + "metadata": { + "description": "Governance Module Account", + "name": "Governance" + }, "operator": "dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky" }, "owner_shares": [ diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index bf7a99cf2c..0007ebff2d 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -2273,6 +2273,8 @@ function edit_genesis() { dasel put -t int -f "$GENESIS" ".app_state.vault.default_quoting_params.spread_min_ppm" -v '3000' # Set operator params. dasel put -t string -f "$GENESIS" ".app_state.vault.operator_params.operator" -v 'dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky' + dasel put -t string -f "$GENESIS" ".app_state.vault.operator_params.metadata.name" -v 'Governance' + dasel put -t string -f "$GENESIS" ".app_state.vault.operator_params.metadata.description" -v 'Governance Module Account' # Set total shares and owner shares. if [ -z "${INPUT_TEST_ACCOUNTS[0]}" ]; then vault_owner_address='dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4' # alice as default vault owner diff --git a/protocol/testutil/constants/genesis.go b/protocol/testutil/constants/genesis.go index ba7c2f1402..7c78b3a6ee 100644 --- a/protocol/testutil/constants/genesis.go +++ b/protocol/testutil/constants/genesis.go @@ -4594,7 +4594,11 @@ const GenesisState = `{ "activation_threshold_quote_quantums": "1000000000" }, "operator_params": { - "operator": "dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky" + "operator": "dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky", + "metadata": { + "name": "Governance", + "description": "Governance Module Account" + } }, "owner_shares": [], "total_shares": { diff --git a/protocol/x/vault/keeper/grpc_query_test.go b/protocol/x/vault/keeper/grpc_query_test.go index 2d9cd9a98f..3c76648104 100644 --- a/protocol/x/vault/keeper/grpc_query_test.go +++ b/protocol/x/vault/keeper/grpc_query_test.go @@ -27,6 +27,7 @@ func TestQueryParams(t *testing.T) { DefaultQuotingParams: types.DefaultQuotingParams(), OperatorParams: types.OperatorParams{ Operator: constants.GovAuthority, + Metadata: types.DefaultOperatorParams().Metadata, }, }, err: nil, diff --git a/protocol/x/vault/keeper/params_test.go b/protocol/x/vault/keeper/params_test.go index 3a22c7cec3..5d1135c383 100644 --- a/protocol/x/vault/keeper/params_test.go +++ b/protocol/x/vault/keeper/params_test.go @@ -389,6 +389,7 @@ func TestGetSetOperatorParams(t *testing.T) { t, vaulttypes.OperatorParams{ Operator: constants.GovAuthority, + Metadata: vaulttypes.DefaultOperatorParams().Metadata, }, params, ) @@ -396,6 +397,10 @@ func TestGetSetOperatorParams(t *testing.T) { // Set operator to Alice. newParams := vaulttypes.OperatorParams{ Operator: constants.AliceAccAddress.String(), + Metadata: vaulttypes.OperatorMetadata{ + Name: "Alice", + Description: "Alice is a community-elected individual", + }, } err := k.SetOperatorParams(ctx, newParams) require.NoError(t, err) diff --git a/protocol/x/vault/types/params.go b/protocol/x/vault/types/params.go index 578f7030cb..31131dac03 100644 --- a/protocol/x/vault/types/params.go +++ b/protocol/x/vault/types/params.go @@ -85,5 +85,9 @@ func (o OperatorParams) Validate() error { func DefaultOperatorParams() OperatorParams { return OperatorParams{ Operator: lib.GovModuleAddress.String(), + Metadata: OperatorMetadata{ + Name: "Governance", + Description: "Governance Module Account", + }, } } diff --git a/protocol/x/vault/types/params.pb.go b/protocol/x/vault/types/params.pb.go index 3c2908369c..e19c7c7ec3 100644 --- a/protocol/x/vault/types/params.pb.go +++ b/protocol/x/vault/types/params.pb.go @@ -181,7 +181,10 @@ func (m *VaultParams) GetQuotingParams() *QuotingParams { // OperatorParams stores parameters regarding megavault operator. type OperatorParams struct { + // Address of the operator. Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"` + // Metadata of the operator. + Metadata OperatorMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata"` } func (m *OperatorParams) Reset() { *m = OperatorParams{} } @@ -224,6 +227,68 @@ func (m *OperatorParams) GetOperator() string { return "" } +func (m *OperatorParams) GetMetadata() OperatorMetadata { + if m != nil { + return m.Metadata + } + return OperatorMetadata{} +} + +// OperatorMetadata stores metadata regarding megavault operator. +type OperatorMetadata struct { + // Name of the operator. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Description of the operator. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *OperatorMetadata) Reset() { *m = OperatorMetadata{} } +func (m *OperatorMetadata) String() string { return proto.CompactTextString(m) } +func (*OperatorMetadata) ProtoMessage() {} +func (*OperatorMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_6043e0b8bfdbca9f, []int{3} +} +func (m *OperatorMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OperatorMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OperatorMetadata.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 *OperatorMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperatorMetadata.Merge(m, src) +} +func (m *OperatorMetadata) XXX_Size() int { + return m.Size() +} +func (m *OperatorMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_OperatorMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_OperatorMetadata proto.InternalMessageInfo + +func (m *OperatorMetadata) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *OperatorMetadata) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + // Deprecated: Params stores `x/vault` parameters. // Deprecated since v6.x as is replaced by QuotingParams. type Params struct { @@ -253,7 +318,7 @@ func (m *Params) Reset() { *m = Params{} } func (m *Params) String() string { return proto.CompactTextString(m) } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_6043e0b8bfdbca9f, []int{3} + return fileDescriptor_6043e0b8bfdbca9f, []int{4} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -328,46 +393,51 @@ func init() { proto.RegisterType((*QuotingParams)(nil), "dydxprotocol.vault.QuotingParams") proto.RegisterType((*VaultParams)(nil), "dydxprotocol.vault.VaultParams") proto.RegisterType((*OperatorParams)(nil), "dydxprotocol.vault.OperatorParams") + proto.RegisterType((*OperatorMetadata)(nil), "dydxprotocol.vault.OperatorMetadata") proto.RegisterType((*Params)(nil), "dydxprotocol.vault.Params") } func init() { proto.RegisterFile("dydxprotocol/vault/params.proto", fileDescriptor_6043e0b8bfdbca9f) } var fileDescriptor_6043e0b8bfdbca9f = []byte{ - // 527 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xb1, 0x6e, 0xd3, 0x40, - 0x1c, 0xc6, 0x63, 0x02, 0x01, 0xae, 0x4d, 0x2a, 0xac, 0xaa, 0x32, 0x1d, 0x9c, 0x10, 0x10, 0xaa, - 0x40, 0xb5, 0xa5, 0x52, 0xa9, 0x8c, 0x10, 0x89, 0xaa, 0x0c, 0x88, 0xc4, 0x46, 0x0c, 0x2c, 0xa7, - 0x8b, 0x7d, 0x71, 0x4e, 0xd8, 0xbe, 0xcb, 0xdd, 0xb9, 0x24, 0x79, 0x8a, 0x6e, 0x0c, 0x6c, 0x3c, - 0x03, 0x0f, 0xd1, 0xb1, 0x62, 0x42, 0x0c, 0x15, 0x4a, 0x5e, 0x04, 0xf9, 0x7f, 0x26, 0xb4, 0xa2, - 0x03, 0x23, 0x03, 0x4b, 0x94, 0xfb, 0xbe, 0xdf, 0xff, 0xfe, 0x27, 0x7d, 0x9f, 0x8c, 0xda, 0xf1, - 0x2c, 0x9e, 0x0a, 0xc9, 0x35, 0x8f, 0x78, 0xea, 0x1f, 0x93, 0x22, 0xd5, 0xbe, 0x20, 0x92, 0x64, - 0xca, 0x03, 0xd5, 0xb6, 0x2f, 0x02, 0x1e, 0x00, 0xdb, 0x77, 0x23, 0xae, 0x32, 0xae, 0x30, 0xc8, - 0xbe, 0x39, 0x18, 0x7c, 0xdb, 0xbd, 0xe2, 0x3e, 0xf8, 0xad, 0xfc, 0xcd, 0x84, 0x27, 0xdc, 0xcc, - 0x95, 0xff, 0x8c, 0xda, 0xfd, 0x5c, 0x47, 0xcd, 0x41, 0xc1, 0x35, 0xcb, 0x93, 0x3e, 0x2c, 0xb7, - 0xb7, 0x50, 0x23, 0x25, 0x33, 0x2a, 0x95, 0x63, 0x75, 0xac, 0x9d, 0x66, 0x50, 0x9d, 0xec, 0x07, - 0xa8, 0xa5, 0x84, 0xa4, 0x24, 0xc6, 0x19, 0xcb, 0xb1, 0x10, 0x99, 0x73, 0x0d, 0xfc, 0x75, 0xa3, - 0xbe, 0x62, 0x79, 0x5f, 0x64, 0xf6, 0x23, 0x74, 0xa7, 0xa2, 0x86, 0xc5, 0x68, 0x44, 0x25, 0x80, - 0x75, 0x00, 0x37, 0x8c, 0xd1, 0x03, 0xbd, 0x64, 0x1f, 0xa2, 0x0d, 0xf5, 0x9e, 0x7e, 0xc0, 0x23, - 0x12, 0x69, 0x6e, 0xc8, 0xeb, 0x40, 0x36, 0x4b, 0xf9, 0x10, 0xd4, 0x92, 0x7b, 0x8c, 0x6c, 0x2e, - 0x63, 0x2a, 0xb1, 0x62, 0x73, 0x8a, 0x45, 0xa4, 0x01, 0xbd, 0x61, 0x2e, 0x05, 0x27, 0x64, 0x73, - 0xda, 0x8f, 0x74, 0x09, 0x3f, 0x45, 0x8e, 0x81, 0xe9, 0x54, 0x30, 0x49, 0x34, 0xe3, 0x39, 0x56, - 0x34, 0xe2, 0x79, 0xac, 0x9c, 0x06, 0x8c, 0x6c, 0x81, 0xff, 0x62, 0x65, 0x87, 0xc6, 0xb5, 0x3f, - 0x5a, 0xe8, 0x3e, 0x89, 0x34, 0x3b, 0x36, 0x43, 0x7a, 0x2c, 0xa9, 0x1a, 0xf3, 0x34, 0xc6, 0x93, - 0x82, 0x6b, 0x8a, 0x27, 0x05, 0xc9, 0x75, 0x91, 0x29, 0xe7, 0x66, 0xc7, 0xda, 0x59, 0xef, 0x1d, - 0x9d, 0x9e, 0xb7, 0x6b, 0xdf, 0xcf, 0xdb, 0xcf, 0x12, 0xa6, 0xc7, 0xc5, 0xd0, 0x8b, 0x78, 0xe6, - 0x5f, 0x4e, 0x60, 0x7f, 0x37, 0x1a, 0x13, 0x96, 0xfb, 0x2b, 0x25, 0xd6, 0x33, 0x41, 0x95, 0x17, - 0x52, 0xc9, 0x48, 0xca, 0xe6, 0x64, 0x98, 0xd2, 0x97, 0xb9, 0x0e, 0x3a, 0xbf, 0x97, 0xbe, 0xf9, - 0xb5, 0xb3, 0x8c, 0x84, 0x0e, 0xaa, 0x8d, 0xdd, 0x13, 0x0b, 0xad, 0xbd, 0x2d, 0xa3, 0xac, 0x22, - 0x3a, 0x40, 0x0d, 0xa5, 0x89, 0x2e, 0x4c, 0x44, 0xad, 0xbd, 0xb6, 0xf7, 0x67, 0x55, 0x3c, 0x18, - 0x08, 0x01, 0x0b, 0x2a, 0xdc, 0x3e, 0x42, 0xad, 0x89, 0x09, 0x1b, 0x9b, 0xaa, 0x41, 0x86, 0x6b, - 0x7b, 0xf7, 0xae, 0xba, 0xe0, 0x52, 0x2d, 0x82, 0xe6, 0xe4, 0xe2, 0xb1, 0x7b, 0x88, 0x5a, 0xaf, - 0x05, 0x95, 0xa4, 0x8c, 0xc8, 0x3c, 0x6a, 0x1f, 0xdd, 0xe2, 0x95, 0x02, 0xcf, 0xba, 0xdd, 0x73, - 0xbe, 0x7e, 0xd9, 0xdd, 0xac, 0x3a, 0xfa, 0x3c, 0x8e, 0x25, 0x55, 0x2a, 0xd4, 0x92, 0xe5, 0x49, - 0xb0, 0x22, 0xbb, 0x9f, 0xea, 0xa8, 0xf1, 0xbf, 0x78, 0xff, 0x68, 0xf1, 0x7a, 0x83, 0xd3, 0x85, - 0x6b, 0x9d, 0x2d, 0x5c, 0xeb, 0xc7, 0xc2, 0xb5, 0x4e, 0x96, 0x6e, 0xed, 0x6c, 0xe9, 0xd6, 0xbe, - 0x2d, 0xdd, 0xda, 0xbb, 0x83, 0xbf, 0xdf, 0x3e, 0xad, 0x3e, 0x46, 0xf0, 0x88, 0x61, 0x03, 0xf4, - 0x27, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x00, 0x8f, 0x94, 0x49, 0xff, 0x04, 0x00, 0x00, + // 587 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x63, 0x12, 0x42, 0x7b, 0x69, 0x52, 0x38, 0x55, 0x95, 0xe9, 0xe0, 0x84, 0x50, 0xa1, + 0x0a, 0x54, 0x47, 0x2a, 0x95, 0xca, 0x08, 0x91, 0xa8, 0xc2, 0x50, 0x91, 0x38, 0x88, 0x81, 0xc5, + 0xba, 0xd8, 0x97, 0xe4, 0x84, 0xed, 0x73, 0xee, 0xce, 0x25, 0xc9, 0x87, 0x40, 0xdd, 0x18, 0xd8, + 0xf8, 0x0c, 0x7c, 0x88, 0x8e, 0x15, 0x13, 0x62, 0xa8, 0x50, 0xf2, 0x45, 0x90, 0xdf, 0xb9, 0x21, + 0x85, 0x0c, 0x8c, 0x0c, 0x5d, 0xac, 0xbb, 0xff, 0xfb, 0xbd, 0x7b, 0x4f, 0xf7, 0x7f, 0x67, 0x54, + 0xf5, 0x27, 0xfe, 0x38, 0x16, 0x5c, 0x71, 0x8f, 0x07, 0x8d, 0x53, 0x92, 0x04, 0xaa, 0x11, 0x13, + 0x41, 0x42, 0x69, 0x83, 0x8a, 0xf1, 0x32, 0x60, 0x03, 0xb0, 0x73, 0xdf, 0xe3, 0x32, 0xe4, 0xd2, + 0x05, 0xb9, 0xa1, 0x37, 0x1a, 0xdf, 0xb1, 0x56, 0x9c, 0x07, 0xdf, 0x2c, 0xbe, 0x35, 0xe0, 0x03, + 0xae, 0xf3, 0xd2, 0x95, 0x56, 0xeb, 0x5f, 0xf2, 0xa8, 0xdc, 0x49, 0xb8, 0x62, 0xd1, 0xa0, 0x0d, + 0xc5, 0xf1, 0x36, 0x2a, 0x06, 0x64, 0x42, 0x85, 0x34, 0x8d, 0x9a, 0xb1, 0x57, 0x76, 0xb2, 0x1d, + 0xde, 0x45, 0x15, 0x19, 0x0b, 0x4a, 0x7c, 0x37, 0x64, 0x91, 0x1b, 0xc7, 0xa1, 0x79, 0x0b, 0xe2, + 0x1b, 0x5a, 0x3d, 0x61, 0x51, 0x3b, 0x0e, 0xf1, 0x63, 0x74, 0x2f, 0xa3, 0x7a, 0x49, 0xbf, 0x4f, + 0x05, 0x80, 0x79, 0x00, 0x37, 0x75, 0xa0, 0x09, 0x7a, 0xca, 0x3e, 0x42, 0x9b, 0xf2, 0x3d, 0xfd, + 0xe0, 0xf6, 0x89, 0xa7, 0xb8, 0x26, 0x0b, 0x40, 0x96, 0x53, 0xf9, 0x18, 0xd4, 0x94, 0x7b, 0x82, + 0x30, 0x17, 0x3e, 0x15, 0xae, 0x64, 0x53, 0xea, 0xc6, 0x9e, 0x02, 0xf4, 0xb6, 0x3e, 0x14, 0x22, + 0x5d, 0x36, 0xa5, 0x6d, 0x4f, 0xa5, 0xf0, 0x33, 0x64, 0x6a, 0x98, 0x8e, 0x63, 0x26, 0x88, 0x62, + 0x3c, 0x72, 0x25, 0xf5, 0x78, 0xe4, 0x4b, 0xb3, 0x08, 0x29, 0xdb, 0x10, 0x7f, 0xb9, 0x08, 0x77, + 0x75, 0x14, 0x7f, 0x32, 0xd0, 0x43, 0xe2, 0x29, 0x76, 0xaa, 0x93, 0xd4, 0x50, 0x50, 0x39, 0xe4, + 0x81, 0xef, 0x8e, 0x12, 0xae, 0xa8, 0x3b, 0x4a, 0x48, 0xa4, 0x92, 0x50, 0x9a, 0x77, 0x6a, 0xc6, + 0xde, 0x46, 0xb3, 0x75, 0x7e, 0x59, 0xcd, 0xfd, 0xb8, 0xac, 0x3e, 0x1f, 0x30, 0x35, 0x4c, 0x7a, + 0xb6, 0xc7, 0xc3, 0xc6, 0x75, 0x07, 0x0e, 0xf7, 0xbd, 0x21, 0x61, 0x51, 0x63, 0xa1, 0xf8, 0x6a, + 0x12, 0x53, 0x69, 0x77, 0xa9, 0x60, 0x24, 0x60, 0x53, 0xd2, 0x0b, 0xe8, 0xab, 0x48, 0x39, 0xb5, + 0xdf, 0x45, 0xdf, 0x5c, 0xd5, 0x4c, 0x2d, 0xa1, 0x9d, 0xac, 0x62, 0xfd, 0xcc, 0x40, 0xa5, 0xb7, + 0xa9, 0x95, 0x99, 0x45, 0x47, 0xa8, 0x28, 0x15, 0x51, 0x89, 0xb6, 0xa8, 0x72, 0x50, 0xb5, 0xff, + 0x1e, 0x15, 0x1b, 0x12, 0xba, 0x80, 0x39, 0x19, 0x8e, 0x5b, 0xa8, 0x32, 0xd2, 0x66, 0xbb, 0x7a, + 0xd4, 0xc0, 0xc3, 0xd2, 0xc1, 0x83, 0x55, 0x07, 0x5c, 0x1b, 0x0b, 0xa7, 0x3c, 0x5a, 0xde, 0xd6, + 0x3f, 0x1a, 0xa8, 0xf2, 0x3a, 0xa6, 0x82, 0xa4, 0x1e, 0xe9, 0xae, 0x0e, 0xd1, 0x1a, 0xcf, 0x14, + 0xe8, 0x6b, 0xbd, 0x69, 0x7e, 0xfb, 0xba, 0xbf, 0x95, 0x0d, 0xe9, 0x0b, 0xdf, 0x17, 0x54, 0xca, + 0xae, 0x12, 0x2c, 0x1a, 0x38, 0x0b, 0x12, 0x1f, 0xa3, 0xb5, 0x90, 0x2a, 0xe2, 0x13, 0x45, 0xb2, + 0x66, 0x76, 0x57, 0x35, 0x73, 0x55, 0xeb, 0x24, 0x63, 0x9b, 0x85, 0xf4, 0xfe, 0x9d, 0x45, 0x6e, + 0xbd, 0x85, 0xee, 0xfe, 0xc9, 0x60, 0x8c, 0x0a, 0x11, 0x09, 0xa9, 0xee, 0xc6, 0x81, 0x35, 0xae, + 0xa1, 0x92, 0x4f, 0xa5, 0x27, 0x58, 0x9c, 0x5e, 0x38, 0x94, 0x5c, 0x77, 0x96, 0xa5, 0xfa, 0xe7, + 0x3c, 0x2a, 0xde, 0xbc, 0x85, 0xff, 0xf4, 0x2d, 0x34, 0x3b, 0xe7, 0x33, 0xcb, 0xb8, 0x98, 0x59, + 0xc6, 0xcf, 0x99, 0x65, 0x9c, 0xcd, 0xad, 0xdc, 0xc5, 0xdc, 0xca, 0x7d, 0x9f, 0x5b, 0xb9, 0x77, + 0x47, 0xff, 0x5e, 0x7d, 0x9c, 0xfd, 0x1f, 0xa1, 0x89, 0x5e, 0x11, 0xf4, 0xa7, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0xb0, 0x1c, 0x9f, 0x45, 0x92, 0x05, 0x00, 0x00, } func (m *QuotingParams) Marshal() (dAtA []byte, err error) { @@ -493,6 +563,16 @@ func (m *OperatorParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 if len(m.Operator) > 0 { i -= len(m.Operator) copy(dAtA[i:], m.Operator) @@ -503,6 +583,43 @@ func (m *OperatorParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *OperatorMetadata) 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 *OperatorMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OperatorMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintParams(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintParams(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Params) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -632,6 +749,25 @@ func (m *OperatorParams) Size() (n int) { if l > 0 { n += 1 + l + sovParams(uint64(l)) } + l = m.Metadata.Size() + n += 1 + l + sovParams(uint64(l)) + return n +} + +func (m *OperatorMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovParams(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovParams(uint64(l)) + } return n } @@ -1033,6 +1169,153 @@ func (m *OperatorParams) Unmarshal(dAtA []byte) error { } m.Operator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OperatorMetadata) 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 ErrIntOverflowParams + } + 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: OperatorMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OperatorMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From cc021fffb2cf6cbc2c8be0f7eba99bcb2b7847be Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:59:04 -0600 Subject: [PATCH 089/120] Rename MATIC to POL in genesis and tests (#2503) --- .../static_exchange_market_config_test.go | 9 +- .../testdata/matic_exchange_config.json | 42 - .../testdata/pol_exchange_config.json | 27 + .../handler/exchange_query_handler_test.go | 5 +- protocol/daemons/slinky/config/market.json | 3031 ----------------- protocol/daemons/slinky/config/oracle.json | 491 --- .../scripts/genesis/sample_pregenesis.json | 122 +- .../containertest/preupgrade_genesis.json | 53 +- protocol/testing/genesis.sh | 49 +- protocol/testing/mainnet/genesis.json | 6 +- protocol/testing/testnet-dev/dev.sh | 4 +- protocol/testing/testnet-staging/staging.sh | 4 +- protocol/testing/testnet/genesis.json | 6 +- protocol/testutil/constants/genesis.go | 126 +- protocol/testutil/constants/pricefeed.go | 6 +- protocol/testutil/constants/prices.go | 32 +- .../pricefeed/exchange_config/market_id.go | 4 +- .../exchange_config/static_market_names.go | 68 +- .../testnet_exchange_market_config.go | 39 +- 19 files changed, 248 insertions(+), 3876 deletions(-) delete mode 100644 protocol/daemons/pricefeed/client/constants/testdata/matic_exchange_config.json create mode 100644 protocol/daemons/pricefeed/client/constants/testdata/pol_exchange_config.json delete mode 100644 protocol/daemons/slinky/config/market.json delete mode 100644 protocol/daemons/slinky/config/oracle.json diff --git a/protocol/daemons/pricefeed/client/constants/static_exchange_market_config_test.go b/protocol/daemons/pricefeed/client/constants/static_exchange_market_config_test.go index 3e3d0cdb04..e5e9585ec3 100644 --- a/protocol/daemons/pricefeed/client/constants/static_exchange_market_config_test.go +++ b/protocol/daemons/pricefeed/client/constants/static_exchange_market_config_test.go @@ -1,9 +1,10 @@ package constants import ( - "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed/exchange_config" "testing" + "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed/exchange_config" + "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/types" "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed" "github.com/dydxprotocol/v4-chain/protocol/testutil/json" @@ -27,9 +28,9 @@ func TestGenerateExchangeConfigJson(t *testing.T) { id: exchange_config.MARKET_LINK_USD, expectedExchangeConfigJsonFile: "link_exchange_config.json", }, - "MATIC exchange config": { - id: exchange_config.MARKET_MATIC_USD, - expectedExchangeConfigJsonFile: "matic_exchange_config.json", + "POL exchange config": { + id: exchange_config.MARKET_POL_USD, + expectedExchangeConfigJsonFile: "pol_exchange_config.json", }, "CRV exchange config": { id: exchange_config.MARKET_CRV_USD, diff --git a/protocol/daemons/pricefeed/client/constants/testdata/matic_exchange_config.json b/protocol/daemons/pricefeed/client/constants/testdata/matic_exchange_config.json deleted file mode 100644 index 80c78dc0fd..0000000000 --- a/protocol/daemons/pricefeed/client/constants/testdata/matic_exchange_config.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "exchanges": [ - { - "exchangeName": "Binance", - "ticker": "MATICUSDT", - "adjustByMarket": "USDT-USD" - }, - { - "exchangeName": "Bybit", - "ticker": "MATICUSDT", - "adjustByMarket": "USDT-USD" - }, - { - "exchangeName": "CoinbasePro", - "ticker": "MATIC-USD" - }, - { - "exchangeName": "Gate", - "ticker": "MATIC_USDT", - "adjustByMarket": "USDT-USD" - }, - { - "exchangeName": "Huobi", - "ticker": "maticusdt", - "adjustByMarket": "USDT-USD" - }, - { - "exchangeName": "Kraken", - "ticker": "MATICUSD" - }, - { - "exchangeName": "Kucoin", - "ticker": "MATIC-USDT", - "adjustByMarket": "USDT-USD" - }, - { - "exchangeName": "Okx", - "ticker": "MATIC-USDT", - "adjustByMarket": "USDT-USD" - } - ] -} diff --git a/protocol/daemons/pricefeed/client/constants/testdata/pol_exchange_config.json b/protocol/daemons/pricefeed/client/constants/testdata/pol_exchange_config.json new file mode 100644 index 0000000000..ba784b1f20 --- /dev/null +++ b/protocol/daemons/pricefeed/client/constants/testdata/pol_exchange_config.json @@ -0,0 +1,27 @@ +{ + "exchanges": [ + { + "exchangeName": "Binance", + "ticker": "POLUSDT", + "adjustByMarket": "USDT-USD" + }, + { + "exchangeName": "Bybit", + "ticker": "POLUSDT", + "adjustByMarket": "USDT-USD" + }, + { + "exchangeName": "CoinbasePro", + "ticker": "POL-USD" + }, + { + "exchangeName": "CryptoCom", + "ticker": "POL_USD" + }, + { + "exchangeName": "Okx", + "ticker": "POL-USDT", + "adjustByMarket": "USDT-USD" + } + ] +} diff --git a/protocol/daemons/pricefeed/client/handler/exchange_query_handler_test.go b/protocol/daemons/pricefeed/client/handler/exchange_query_handler_test.go index b276a8b336..ac9c42273d 100644 --- a/protocol/daemons/pricefeed/client/handler/exchange_query_handler_test.go +++ b/protocol/daemons/pricefeed/client/handler/exchange_query_handler_test.go @@ -4,11 +4,12 @@ import ( "context" "errors" "fmt" - "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed/exchange_config" "net/http" "testing" "time" + "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed/exchange_config" + pf_constants "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/constants" "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/price_function" "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/types" @@ -310,7 +311,7 @@ func generateTestMarketPriceExponentMap() map[types.MarketId]types.Exponent { marketExponents[exchange_config.MARKET_BTC_USD] = constants.BtcUsdExponent marketExponents[exchange_config.MARKET_ETH_USD] = constants.EthUsdExponent marketExponents[exchange_config.MARKET_LINK_USD] = constants.LinkUsdExponent - marketExponents[exchange_config.MARKET_MATIC_USD] = constants.MaticUsdExponent + marketExponents[exchange_config.MARKET_POL_USD] = constants.PolUsdExponent marketExponents[exchange_config.MARKET_CRV_USD] = constants.CrvUsdExponent marketExponents[unavailableId] = unavailableExponent return marketExponents diff --git a/protocol/daemons/slinky/config/market.json b/protocol/daemons/slinky/config/market.json deleted file mode 100644 index 82e9654b73..0000000000 --- a/protocol/daemons/slinky/config/market.json +++ /dev/null @@ -1,3031 +0,0 @@ -{ - "tickers": { - "ADA/USD": { - "currency_pair": { - "Base": "ADA", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ADA/USDC": { - "currency_pair": { - "Base": "ADA", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ADA/USDT": { - "currency_pair": { - "Base": "ADA", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APE/USD": { - "currency_pair": { - "Base": "APE", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APE/USDC": { - "currency_pair": { - "Base": "APE", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APE/USDT": { - "currency_pair": { - "Base": "APE", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APT/USD": { - "currency_pair": { - "Base": "APT", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APT/USDC": { - "currency_pair": { - "Base": "APT", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "APT/USDT": { - "currency_pair": { - "Base": "APT", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ARB/USD": { - "currency_pair": { - "Base": "ARB", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ARB/USDT": { - "currency_pair": { - "Base": "ARB", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ATOM/USD": { - "currency_pair": { - "Base": "ATOM", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ATOM/USDC": { - "currency_pair": { - "Base": "ATOM", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ATOM/USDT": { - "currency_pair": { - "Base": "ATOM", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "AVAX/USD": { - "currency_pair": { - "Base": "AVAX", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "AVAX/USDC": { - "currency_pair": { - "Base": "AVAX", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "AVAX/USDT": { - "currency_pair": { - "Base": "AVAX", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BCH/USD": { - "currency_pair": { - "Base": "BCH", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BCH/USDT": { - "currency_pair": { - "Base": "BCH", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BLUR/USD": { - "currency_pair": { - "Base": "BLUR", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BLUR/USDT": { - "currency_pair": { - "Base": "BLUR", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BTC/USD": { - "currency_pair": { - "Base": "BTC", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BTC/USDC": { - "currency_pair": { - "Base": "BTC", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "BTC/USDT": { - "currency_pair": { - "Base": "BTC", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "COMP/USD": { - "currency_pair": { - "Base": "COMP", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "COMP/USDT": { - "currency_pair": { - "Base": "COMP", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "CRV/USD": { - "currency_pair": { - "Base": "CRV", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "CRV/USDT": { - "currency_pair": { - "Base": "CRV", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "DOGE/USD": { - "currency_pair": { - "Base": "DOGE", - "Quote": "USD" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "DOGE/USDT": { - "currency_pair": { - "Base": "DOGE", - "Quote": "USDT" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "DOT/USD": { - "currency_pair": { - "Base": "DOT", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "DOT/USDT": { - "currency_pair": { - "Base": "DOT", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "DYDX/USD": { - "currency_pair": { - "Base": "DYDX", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "DYDX/USDC": { - "currency_pair": { - "Base": "DYDX", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "DYDX/USDT": { - "currency_pair": { - "Base": "DYDX", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETC/USD": { - "currency_pair": { - "Base": "ETC", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETC/USDT": { - "currency_pair": { - "Base": "ETC", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETH/BTC": { - "currency_pair": { - "Base": "ETH", - "Quote": "BTC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETH/USD": { - "currency_pair": { - "Base": "ETH", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETH/USDC": { - "currency_pair": { - "Base": "ETH", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "ETH/USDT": { - "currency_pair": { - "Base": "ETH", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "FIL/USD": { - "currency_pair": { - "Base": "FIL", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "FIL/USDT": { - "currency_pair": { - "Base": "FIL", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LDO/USD": { - "currency_pair": { - "Base": "LDO", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LDO/USDT": { - "currency_pair": { - "Base": "LDO", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LINK/USD": { - "currency_pair": { - "Base": "LINK", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LINK/USDT": { - "currency_pair": { - "Base": "LINK", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LTC/USD": { - "currency_pair": { - "Base": "LTC", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "LTC/USDT": { - "currency_pair": { - "Base": "LTC", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "MATIC/USD": { - "currency_pair": { - "Base": "MATIC", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "MATIC/USDT": { - "currency_pair": { - "Base": "MATIC", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "MKR/USD": { - "currency_pair": { - "Base": "MKR", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "MKR/USDT": { - "currency_pair": { - "Base": "MKR", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "MOG/USD": { - "currency_pair": { - "Base": "MOG", - "Quote": "USD" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "NEAR/USD": { - "currency_pair": { - "Base": "NEAR", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "NEAR/USDT": { - "currency_pair": { - "Base": "NEAR", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "OP/USD": { - "currency_pair": { - "Base": "OP", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "OP/USDT": { - "currency_pair": { - "Base": "OP", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "OSMO/USD": { - "currency_pair": { - "Base": "OSMO", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "OSMO/USDC": { - "currency_pair": { - "Base": "OSMO", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "OSMO/USDT": { - "currency_pair": { - "Base": "OSMO", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "PEPE/USD": { - "currency_pair": { - "Base": "PEPE", - "Quote": "USD" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "PEPE/USDT": { - "currency_pair": { - "Base": "PEPE", - "Quote": "USDT" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "SEI/USD": { - "currency_pair": { - "Base": "SEI", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SEI/USDT": { - "currency_pair": { - "Base": "SEI", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SHIB/USD": { - "currency_pair": { - "Base": "SHIB", - "Quote": "USD" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "SHIB/USDT": { - "currency_pair": { - "Base": "SHIB", - "Quote": "USDT" - }, - "decimals": 18, - "min_provider_count": 1 - }, - "SOL/USD": { - "currency_pair": { - "Base": "SOL", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SOL/USDC": { - "currency_pair": { - "Base": "SOL", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SOL/USDT": { - "currency_pair": { - "Base": "SOL", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SUI/USD": { - "currency_pair": { - "Base": "SUI", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "SUI/USDT": { - "currency_pair": { - "Base": "SUI", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "TIA/USD": { - "currency_pair": { - "Base": "TIA", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "TIA/USDC": { - "currency_pair": { - "Base": "TIA", - "Quote": "USDC" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "TIA/USDT": { - "currency_pair": { - "Base": "TIA", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "TRX/USD": { - "currency_pair": { - "Base": "TRX", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "TRX/USDT": { - "currency_pair": { - "Base": "TRX", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "UNI/USD": { - "currency_pair": { - "Base": "UNI", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "UNI/USDT": { - "currency_pair": { - "Base": "UNI", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "USDC/USD": { - "currency_pair": { - "Base": "USDC", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "USDC/USDT": { - "currency_pair": { - "Base": "USDC", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "USDT/USD": { - "currency_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "WLD/USDT": { - "currency_pair": { - "Base": "WLD", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "XLM/USD": { - "currency_pair": { - "Base": "XLM", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "XLM/USDT": { - "currency_pair": { - "Base": "XLM", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "XRP/USD": { - "currency_pair": { - "Base": "XRP", - "Quote": "USD" - }, - "decimals": 8, - "min_provider_count": 1 - }, - "XRP/USDT": { - "currency_pair": { - "Base": "XRP", - "Quote": "USDT" - }, - "decimals": 8, - "min_provider_count": 1 - } - }, - "paths": {}, - "providers": { - "ADA/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ADAUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "ADA/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ADA-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ADA-USD" - }, - { - "name": "Okx", - "off_chain_ticker": "ADA-USD" - } - ] - }, - "ADA/USDC": { - "providers": [ - { - "name": "Mexc", - "off_chain_ticker": "ADAUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ADA-USDC" - }, - { - "name": "Okx", - "off_chain_ticker": "ADA-USDC" - } - ] - }, - "ADA/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ADAUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "ADA_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "adausdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "ADAUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "ADAUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ADA-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "ADAUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "ADA-USDT" - } - ] - }, - "APE/USD": { - "providers": [ - { - "name": "Kraken", - "off_chain_ticker": "APE/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "APE-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "APE-USD" - } - ] - }, - "APE/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "APE-USDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "APE-USDC" - }, - { - "name": "Okx", - "off_chain_ticker": "APE-USDC" - } - ] - }, - "APE/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "APEUSDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "APE-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "APE_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "APEUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "APEUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "APE-USDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "APE-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "APE-USDT" - } - ] - }, - "APT/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "APTUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "APT-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "APT-USD" - } - ] - }, - "APT/USDC": { - "providers": [ - { - "name": "Okx", - "off_chain_ticker": "APT-USDC" - } - ] - }, - "APT/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "APT_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "aptusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "APTUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "APTUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "APT-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "APTUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "APT-USDT" - } - ] - }, - "ARB/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ARBUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ARB-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ARB-USD" - } - ] - }, - "ARB/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "ARB_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "arbusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "ARBUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "ARBUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ARB-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "ARBUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "ARB-USDT" - } - ] - }, - "ATOM/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "cosmos/usd" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "ATOMUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "ATOM/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ATOM-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ATOM-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "ATOMUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "ATOM-USD" - } - ] - }, - "ATOM/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ATOM-USDC" - }, - { - "name": "Mexc", - "off_chain_ticker": "ATOMUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ATOM-USDC" - }, - { - "name": "Okx", - "off_chain_ticker": "ATOM-USDC" - } - ] - }, - "ATOM/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ATOMUSDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ATOM-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "ATOM_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "atomusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "ATOMUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "ATOMUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ATOM-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "ATOMUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ATOM-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "ATOM_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "ATOM-USDT" - } - ] - }, - "AVAX/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "AVAXUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "AVAX/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "AVAX-USD" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "avaxusd" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "AVAX-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "AVAXUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "AVAX-USD" - } - ] - }, - "AVAX/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "AVAX-USDC" - }, - { - "name": "Mexc", - "off_chain_ticker": "AVAXUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "AVAX-USDC" - }, - { - "name": "Bybit", - "off_chain_ticker": "AVAXUSDC" - }, - { - "name": "Okx", - "off_chain_ticker": "AVAX-USDC" - } - ] - }, - "AVAX/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "AVAXUSDT" - }, - { - "name": "Kraken", - "off_chain_ticker": "AVAX/USDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "AVAX-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "AVAX_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "avaxusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "AVAXUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "AVAXUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "AVAX-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "AVAXUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "AVAX-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "AVAX_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "AVAX-USDT" - } - ] - }, - "BCH/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "BCHUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "BCH/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "BCH-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "BCH-USD" - } - ] - }, - "BCH/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "BCHUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "BCH_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "bchusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "BCHUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "BCHUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "BCH-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "BCHUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "BCH-USDT" - } - ] - }, - "BLUR/USD": { - "providers": [ - { - "name": "Kraken", - "off_chain_ticker": "BLUR/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "BLUR-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "BLUR-USD" - } - ] - }, - "BLUR/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "BLUR_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "BLURUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "BLUR-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "BLUR-USDT" - } - ] - }, - "BTC/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "bitcoin/usd" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "XXBTZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "XBT/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "BTC-USD" - }, - { - "name": "Bitfinex", - "off_chain_ticker": "BTCUSD" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "btcusd" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "BTC-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "BTCUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "BTC-USD" - } - ] - }, - "BTC/USDC": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XBTUSDC" - }, - { - "name": "Kraken", - "off_chain_ticker": "XBT/USDC" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "BTC-USDC" - }, - { - "name": "Huobi", - "off_chain_ticker": "btcusdc" - }, - { - "name": "Mexc", - "off_chain_ticker": "BTCUSDC" - }, - { - "name": "Binance", - "off_chain_ticker": "BTCUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "BTC-USDC" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "btcusdc" - }, - { - "name": "Bybit", - "off_chain_ticker": "BTCUSDC" - }, - { - "name": "Okx", - "off_chain_ticker": "BTC-USDC" - } - ] - }, - "BTC/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XBTUSDT" - }, - { - "name": "Kraken", - "off_chain_ticker": "XBT/USDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "BTC-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "BTC_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "btcusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "BTCUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "BTCUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "BTC-USDT" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "btcusdt" - }, - { - "name": "Bybit", - "off_chain_ticker": "BTCUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "BTC-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "BTC_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "BTC-USDT" - } - ] - }, - "COMP/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "COMPUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "COMP/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "COMP-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "COMP-USD" - } - ] - }, - "COMP/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "COMP_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "COMPUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "COMPUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "COMP-USDT" - } - ] - }, - "CRV/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "CRVUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "CRV/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "CRV-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "CRV-USD" - } - ] - }, - "CRV/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "CRV_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "CRVUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "CRVUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "CRV-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "CRV-USDT" - } - ] - }, - "DOGE/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XDGUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "XDG/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "DOGE-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "DOGE-USD" - } - ] - }, - "DOGE/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XDGUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "DOGE_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "dogeusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "DOGEUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "DOGEUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "DOGE-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "DOGEUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "DOGE-USDT" - } - ] - }, - "DOT/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "DOTUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "DOT/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "DOT-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "DOT-USD" - } - ] - }, - "DOT/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "DOTUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "DOT_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "DOTUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "DOTUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "DOT-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "DOTUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "DOT-USDT" - } - ] - }, - "DYDX/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "dydx-chain/usd" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "DYDXUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "DYDX/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "DYDX-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "DYDXUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "DYDX-USD" - } - ] - }, - "DYDX/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "DYDX-USDC" - } - ] - }, - "DYDX/USDT": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "DYDX-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "DYDX_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "dydxusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "DYDXUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "DYDXUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "DYDX-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "DYDXUSDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "DYDX_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "DYDX-USDT" - } - ] - }, - "ETC/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ETCUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ETC-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ETC-USD" - } - ] - }, - "ETC/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "ETC_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "etcusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "ETCUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "ETCUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ETC-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "ETC-USDT" - } - ] - }, - "ETH/BTC": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "ethereum/btc" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "XETHXXBT" - }, - { - "name": "Kraken", - "off_chain_ticker": "ETH/XBT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ETH-BTC" - }, - { - "name": "Gate", - "off_chain_ticker": "ETH_BTC" - }, - { - "name": "Huobi", - "off_chain_ticker": "ethbtc" - }, - { - "name": "Mexc", - "off_chain_ticker": "ETHBTC" - }, - { - "name": "Binance", - "off_chain_ticker": "ETHBTC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ETH-BTC" - }, - { - "name": "Bitfinex", - "off_chain_ticker": "ETHBTC" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "ethbtc" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ETH-BTC" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "ETH_BTC" - }, - { - "name": "Okx", - "off_chain_ticker": "ETH-BTC" - } - ] - }, - "ETH/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "ethereum/usd" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "XETHZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "ETH/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ETH-USD" - }, - { - "name": "Bitfinex", - "off_chain_ticker": "ETHUSD" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "ethusd" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ETH-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "ETHUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "ETH-USD" - } - ] - }, - "ETH/USDC": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ETHUSDC" - }, - { - "name": "Kraken", - "off_chain_ticker": "ETH/USDC" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ETH-USDC" - }, - { - "name": "Huobi", - "off_chain_ticker": "ethusdc" - }, - { - "name": "Mexc", - "off_chain_ticker": "ETHUSDC" - }, - { - "name": "Binance", - "off_chain_ticker": "ETHUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ETH-USDC" - }, - { - "name": "Bybit", - "off_chain_ticker": "ETHUSDC" - }, - { - "name": "Okx", - "off_chain_ticker": "ETH-USDC" - } - ] - }, - "ETH/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "ETHUSDT" - }, - { - "name": "Kraken", - "off_chain_ticker": "ETH/USDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "ETH-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "ETH_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "ethusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "ETHUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "ETHUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "ETH-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "ETHUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "ETH-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "ETH_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "ETH-USDT" - } - ] - }, - "FIL/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "FILUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "FIL/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "FIL-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "FIL-USD" - } - ] - }, - "FIL/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "FIL_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "filusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "FILUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "FILUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "FIL-USDT" - } - ] - }, - "LDO/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "LDOUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "LDO/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "LDO-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "LDO-USD" - } - ] - }, - "LDO/USDT": { - "providers": [ - { - "name": "Mexc", - "off_chain_ticker": "LDOUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "LDOUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "LDO-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "LDO-USDT" - } - ] - }, - "LINK/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "LINKUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "LINK/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "LINK-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "LINK-USD" - } - ] - }, - "LINK/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "LINKUSDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "LINKUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "LINKUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "LINK-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "LINKUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "LINK-USDT" - } - ] - }, - "LTC/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XLTCZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "XLTCZ/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "LTC-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "LTC-USD" - } - ] - }, - "LTC/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "LTCUSDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "ltcusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "LTCUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "LTCUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "LTC-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "LTCUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "LTC-USDT" - } - ] - }, - "MATIC/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "MATICUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "MATIC/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "MATIC-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "MATIC-USD" - } - ] - }, - "MATIC/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "MATIC_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "maticusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "MATIC-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "MATIC-USDT" - } - ] - }, - "MKR/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "MKRUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "MKR/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "MKR-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "MKR-USD" - } - ] - }, - "MKR/USDT": { - "providers": [ - { - "name": "Mexc", - "off_chain_ticker": "MKRUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "MKRUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "MKR-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "MKR-USDT" - } - ] - }, - "MOG/USD": { - "providers": [ - { - "name": "GeckoTerminal", - "off_chain_ticker": "0xaaee1a9723aadb7afa2810263653a34ba2c21c7a" - } - ] - }, - "NEAR/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "NEARUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "NEAR-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "NEAR-USD" - } - ] - }, - "NEAR/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "NEAR_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "nearusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "NEARUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "NEARUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "NEAR-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "NEAR-USDT" - } - ] - }, - "OP/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "OPUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "OP-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "OP-USD" - } - ] - }, - "OP/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "OP_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "OPUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "OPUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "OP-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "OP-USDT" - } - ] - }, - "OSMO/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "osmosis/usd" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "OSMO-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "OSMO-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "OSMO_USD" - } - ] - }, - "OSMO/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "OSMO-USDC" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "OSMO-USDC" - } - ] - }, - "OSMO/USDT": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "OSMO-USDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "OSMO-USDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "OSMO-USDT" - } - ] - }, - "PEPE/USD": { - "providers": [ - { - "name": "GeckoTerminal", - "off_chain_ticker": "0x6982508145454Ce325dDbE47a25d4ec3d2311933" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "PEPEUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "PEPE/USD" - } - ] - }, - "PEPE/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "PEPE_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "PEPEUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "PEPEUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "PEPE-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "PEPEUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "PEPE-USDT" - } - ] - }, - "SEI/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "SEIUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SEI-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SEI-USD" - } - ] - }, - "SEI/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "SEI_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "seiusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "SEIUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "SEIUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "SEI-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "SEIUSDT" - } - ] - }, - "SHIB/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "SHIBUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "SHIB/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SHIB-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SHIB-USD" - } - ] - }, - "SHIB/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "SHIBUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "SHIB_USDT" - }, - { - "name": "Mexc", - "off_chain_ticker": "SHIBUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "SHIBUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "SHIB-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "SHIBUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "SHIB-USDT" - } - ] - }, - "SOL/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "solana/usd" - }, - { - "name": "KrakenAPI", - "off_chain_ticker": "SOLUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "SOL/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SOL-USD" - }, - { - "name": "Bitfinex", - "off_chain_ticker": "SOLUSD" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "solusd" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SOL-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "SOLUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "SOL-USD" - } - ] - }, - "SOL/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SOL-USDC" - }, - { - "name": "Gate", - "off_chain_ticker": "SOL_USDC" - }, - { - "name": "Mexc", - "off_chain_ticker": "SOLUSDC" - }, - { - "name": "Binance", - "off_chain_ticker": "SOLUSDC" - }, - { - "name": "Kucoin", - "off_chain_ticker": "SOL-USDC" - }, - { - "name": "Bybit", - "off_chain_ticker": "SOLUSDC" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SOL-USDC" - }, - { - "name": "Okx", - "off_chain_ticker": "SOL-USDC" - } - ] - }, - "SOL/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "SOLUSDT" - }, - { - "name": "Kraken", - "off_chain_ticker": "SOL/USDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SOL-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "SOL_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "solusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "SOLUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "SOLUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "SOL-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "SOLUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SOL-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "SOL_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "SOL-USDT" - } - ] - }, - "SUI/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "SUIUSD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "SUI-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "SUI-USD" - } - ] - }, - "SUI/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "SUI_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "suiusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "SUIUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "SUIUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "SUI-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "SUIUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "SUI-USDT" - } - ] - }, - "TIA/USD": { - "providers": [ - { - "name": "Coingecko", - "off_chain_ticker": "celestia/usd" - }, - { - "name": "Kraken", - "off_chain_ticker": "TIA/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "TIA-USD" - }, - { - "name": "Bitfinex", - "off_chain_ticker": "TIAUSD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "TIA-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "TIAUSD-PERP" - }, - { - "name": "Okx", - "off_chain_ticker": "TIA-USD" - } - ] - }, - "TIA/USDC": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "TIA-USDC" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "TIA-USDC" - } - ] - }, - "TIA/USDT": { - "providers": [ - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "TIA-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "TIA_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "tiausdt" - }, - { - "name": "Kucoin", - "off_chain_ticker": "TIA-USDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "TIA-USDT" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "TIA_USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "TIA-USDT" - } - ] - }, - "TRX/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "TRXUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "TRX/USD" - } - ] - }, - "TRX/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "TRX_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "trxusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "TRXUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "TRXUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "TRX-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "TRXUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "TRX-USDT" - } - ] - }, - "UNI/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "UNIUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "UNI/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "UNI-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "UNI-USD" - } - ] - }, - "UNI/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "UNI_USDT" - }, - { - "name": "Binance", - "off_chain_ticker": "UNIUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "UNI-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "UNIUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "UNI-USDT" - } - ] - }, - "USDC/USD": { - "providers": [ - { - "name": "Kraken", - "off_chain_ticker": "USDC/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "USDC-USD" - }, - { - "name": "Okx", - "off_chain_ticker": "USDC-USD" - } - ] - }, - "USDC/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "USDCUSDT" - }, - { - "name": "Kraken", - "off_chain_ticker": "USDC/USDT" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "USDC-USDT" - }, - { - "name": "Gate", - "off_chain_ticker": "USDC_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "usdcusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "USDCUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "USDCUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "USDC-USDT" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "usdcusdt" - }, - { - "name": "Bybit", - "off_chain_ticker": "USDCUSDT" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "USDC-USDT" - }, - { - "name": "Okx", - "off_chain_ticker": "USDC-USDT" - } - ] - }, - "USDT/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "USDTZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "USDT/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "USDT-USD" - }, - { - "name": "Binance", - "off_chain_ticker": "USDTUSD" - }, - { - "name": "Bitstamp", - "off_chain_ticker": "usdtusd" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "USDT-USD" - }, - { - "name": "CryptoCom", - "off_chain_ticker": "USDT_USD" - }, - { - "name": "Okx", - "off_chain_ticker": "USDT-USD" - } - ] - }, - "WLD/USDT": { - "providers": [ - { - "name": "Gate", - "off_chain_ticker": "WLD_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "wldusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "WLDUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "WLDUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "WLD-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "WLDUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "WLD-USDT" - } - ] - }, - "XLM/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XXLMZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "XXLMZ/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "XLM-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "XLM-USD" - } - ] - }, - "XLM/USDT": { - "providers": [ - { - "name": "Mexc", - "off_chain_ticker": "XLMUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "XLMUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "XLM-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "XLMUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "XLM-USDT" - } - ] - }, - "XRP/USD": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XXRPZUSD" - }, - { - "name": "Kraken", - "off_chain_ticker": "XXRPZ/USD" - }, - { - "name": "CoinbaseProAPI", - "off_chain_ticker": "XRP-USD" - }, - { - "name": "CoinbasePro", - "off_chain_ticker": "XRP-USD" - } - ] - }, - "XRP/USDT": { - "providers": [ - { - "name": "KrakenAPI", - "off_chain_ticker": "XRPUSDT" - }, - { - "name": "Gate", - "off_chain_ticker": "XRP_USDT" - }, - { - "name": "Huobi", - "off_chain_ticker": "xrpusdt" - }, - { - "name": "Mexc", - "off_chain_ticker": "XRPUSDT" - }, - { - "name": "Binance", - "off_chain_ticker": "XRPUSDT" - }, - { - "name": "Kucoin", - "off_chain_ticker": "XRP-USDT" - }, - { - "name": "Bybit", - "off_chain_ticker": "XRPUSDT" - }, - { - "name": "Okx", - "off_chain_ticker": "XRP-USDT" - } - ] - } - } -} diff --git a/protocol/daemons/slinky/config/oracle.json b/protocol/daemons/slinky/config/oracle.json deleted file mode 100644 index 23a1738f70..0000000000 --- a/protocol/daemons/slinky/config/oracle.json +++ /dev/null @@ -1,491 +0,0 @@ -{ - "updateInterval": 1500000000, - "maxPriceAge": 120000000000, - "providers": [ - { - "name": "Binance", - "api": { - "enabled": true, - "timeout": 500000000, - "interval": 150000000, - "reconnectTimeout": 2000000000, - "maxQueries": 1, - "atomic": true, - "url": "https://api.binance.com/api/v3/ticker/price?symbols=%s%s%s", - "name": "Binance" - }, - "webSocket": { - "enabled": false, - "maxBufferSize": 0, - "reconnectionTimeout": 0, - "wss": "", - "name": "", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 0, - "enableCompression": false, - "readTimeout": 0, - "writeTimeout": 0, - "pingInterval": 0, - "maxReadErrorCount": 0, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "CoinbaseProAPI", - "api": { - "enabled": true, - "timeout": 500000000, - "interval": 100000000, - "reconnectTimeout": 2000000000, - "maxQueries": 5, - "atomic": false, - "url": "https://api.coinbase.com/v2/prices/%s/spot", - "name": "CoinbaseProAPI" - }, - "webSocket": { - "enabled": false, - "maxBufferSize": 0, - "reconnectionTimeout": 0, - "wss": "", - "name": "", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 0, - "enableCompression": false, - "readTimeout": 0, - "writeTimeout": 0, - "pingInterval": 0, - "maxReadErrorCount": 0, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Coingecko", - "api": { - "enabled": true, - "timeout": 500000000, - "interval": 15000000000, - "reconnectTimeout": 2000000000, - "maxQueries": 1, - "atomic": true, - "url": "https://api.coingecko.com/api/v3", - "name": "Coingecko" - }, - "webSocket": { - "enabled": false, - "maxBufferSize": 0, - "reconnectionTimeout": 0, - "wss": "", - "name": "", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 0, - "enableCompression": false, - "readTimeout": 0, - "writeTimeout": 0, - "pingInterval": 0, - "maxReadErrorCount": 0, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "GeckoTerminal", - "api": { - "enabled": true, - "timeout": 500000000, - "interval": 5000000000, - "reconnectTimeout": 2000000000, - "maxQueries": 1, - "atomic": false, - "url": "https://api.geckoterminal.com/api/v2/simple/networks/eth/token_price/%s", - "name": "GeckoTerminal" - }, - "webSocket": { - "enabled": false, - "maxBufferSize": 0, - "reconnectionTimeout": 0, - "wss": "", - "name": "", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 0, - "enableCompression": false, - "readTimeout": 0, - "writeTimeout": 0, - "pingInterval": 0, - "maxReadErrorCount": 0, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "KrakenAPI", - "api": { - "enabled": true, - "timeout": 500000000, - "interval": 150000000, - "reconnectTimeout": 2000000000, - "maxQueries": 1, - "atomic": true, - "url": "https://api.kraken.com/0/public/Ticker?pair=%s", - "name": "KrakenAPI" - }, - "webSocket": { - "enabled": false, - "maxBufferSize": 0, - "reconnectionTimeout": 0, - "wss": "", - "name": "", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 0, - "enableCompression": false, - "readTimeout": 0, - "writeTimeout": 0, - "pingInterval": 0, - "maxReadErrorCount": 0, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Bitfinex", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://api-pub.bitfinex.com/ws/2", - "name": "Bitfinex", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Bitstamp", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1024, - "reconnectionTimeout": 10000000000, - "wss": "wss://ws.bitstamp.net", - "name": "Bitstamp", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 10000000000, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Bybit", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://stream.bybit.com/v5/public/spot", - "name": "Bybit", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 15000000000, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "CoinbasePro", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1024, - "reconnectionTimeout": 10000000000, - "wss": "wss://ws-feed.exchange.coinbase.com", - "name": "CoinbasePro", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 5000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "CryptoCom", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1024, - "reconnectionTimeout": 10000000000, - "wss": "wss://stream.crypto.com/exchange/v1/market", - "name": "CryptoCom", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Gate", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://api.gateio.ws/ws/v4/", - "name": "Gate", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Huobi", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://api.huobi.pro/ws", - "name": "Huobi", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Kraken", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://ws.kraken.com", - "name": "Kraken", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Kucoin", - "api": { - "enabled": false, - "timeout": 5000000000, - "interval": 60000000000, - "reconnectTimeout": 0, - "maxQueries": 1, - "atomic": false, - "url": "https://api.kucoin.com", - "name": "Kucoin" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1024, - "reconnectionTimeout": 10000000000, - "wss": "wss://ws-api-spot.kucoin.com/", - "name": "Kucoin", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 10000000000, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - }, - { - "name": "Mexc", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://wbs.mexc.com/ws", - "name": "Mexc", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 20000000000, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 20 - }, - "type": "price_provider" - }, - { - "name": "Okx", - "api": { - "enabled": false, - "timeout": 0, - "interval": 0, - "reconnectTimeout": 0, - "maxQueries": 0, - "atomic": false, - "url": "", - "name": "" - }, - "webSocket": { - "enabled": true, - "maxBufferSize": 1000, - "reconnectionTimeout": 10000000000, - "wss": "wss://ws.okx.com:8443/ws/v5/public", - "name": "Okx", - "readBufferSize": 0, - "writeBufferSize": 0, - "handshakeTimeout": 45000000000, - "enableCompression": false, - "readTimeout": 45000000000, - "writeTimeout": 45000000000, - "pingInterval": 0, - "maxReadErrorCount": 100, - "maxSubscriptionsPerConnection": 0 - }, - "type": "price_provider" - } - ], - "production": true, - "metrics": { - "prometheusServerAddress": "0.0.0.0:8002", - "enabled": true - } -} diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index b909f9ffc9..ec979c03d6 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -2069,75 +2069,6 @@ "min_provider_count": 3 } }, - "MATIC/USD": { - "provider_configs": [ - { - "name": "binance_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "bybit_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "MATICUSDT" - }, - { - "name": "coinbase_ws", - "off_chain_ticker": "MATIC-USD" - }, - { - "name": "gate_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "MATIC_USDT" - }, - { - "name": "huobi_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "maticusdt" - }, - { - "name": "kraken_api", - "off_chain_ticker": "MATICUSD" - }, - { - "name": "kucoin_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "MATIC-USDT" - }, - { - "name": "okx_ws", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - }, - "off_chain_ticker": "MATIC-USDT" - } - ], - "ticker": { - "currency_pair": { - "Base": "MATIC", - "Quote": "USD" - }, - "decimals": 10, - "enabled": true, - "min_provider_count": 3 - } - }, "MKR/USD": { "provider_configs": [ { @@ -2346,6 +2277,51 @@ "min_provider_count": 3 } }, + "POL/USD": { + "provider_configs": [ + { + "name": "binance_ws", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + }, + "off_chain_ticker": "POLUSDT" + }, + { + "name": "bybit_ws", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + }, + "off_chain_ticker": "POLUSDT" + }, + { + "name": "coinbase_ws", + "off_chain_ticker": "POL-USD" + }, + { + "name": "crypto_dot_com_ws", + "off_chain_ticker": "POL_USD" + }, + { + "name": "okx_ws", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + }, + "off_chain_ticker": "POL-USDT" + } + ], + "ticker": { + "currency_pair": { + "Base": "POL", + "Quote": "USD" + }, + "decimals": 10, + "enabled": true, + "min_provider_count": 3 + } + }, "SEI/USD": { "provider_configs": [ { @@ -3093,7 +3069,7 @@ "liquidity_tier": 1, "market_id": 3, "market_type": 1, - "ticker": "MATIC-USD" + "ticker": "POL-USD" } }, { @@ -3444,12 +3420,12 @@ "pair": "LINK-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MATIC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"maticusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"MATICUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", + "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 3, "min_exchanges": 3, "min_price_change_ppm": 2500, - "pair": "MATIC-USD" + "pair": "POL-USD" }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"CRVUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"CRV-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"CRV_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"CRVUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", @@ -3719,7 +3695,7 @@ { "exponent": -10, "id": 3, - "price": 6665746387 + "price": 3703925550 }, { "exponent": -10, diff --git a/protocol/testing/containertest/preupgrade_genesis.json b/protocol/testing/containertest/preupgrade_genesis.json index 678634c694..612ed3f5f5 100644 --- a/protocol/testing/containertest/preupgrade_genesis.json +++ b/protocol/testing/containertest/preupgrade_genesis.json @@ -1426,20 +1426,21 @@ } ] }, - "MATIC/USD": { + "POL/USD": { "ticker": { "currency_pair": { - "Base": "MATIC", + "Base": "POL", "Quote": "USD" }, - "decimals": 10, - "min_provider_count": 3, - "enabled": true + "decimals": "10", + "min_provider_count": "3", + "enabled": true, + "metadata_JSON": "" }, "provider_configs": [ { "name": "binance_ws", - "off_chain_ticker": "MATICUSDT", + "off_chain_ticker": "POLUSDT", "normalize_by_pair": { "Base": "USDT", "Quote": "USD" @@ -1447,7 +1448,7 @@ }, { "name": "bybit_ws", - "off_chain_ticker": "MATICUSDT", + "off_chain_ticker": "POLUSDT", "normalize_by_pair": { "Base": "USDT", "Quote": "USD" @@ -1455,39 +1456,15 @@ }, { "name": "coinbase_ws", - "off_chain_ticker": "MATIC-USD" + "off_chain_ticker": "POL-USD" }, { - "name": "gate_ws", - "off_chain_ticker": "MATIC_USDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "huobi_ws", - "off_chain_ticker": "maticusdt", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "kraken_api", - "off_chain_ticker": "MATICUSD" - }, - { - "name": "kucoin_ws", - "off_chain_ticker": "MATIC-USDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } + "name": "crypto_dot_com_ws", + "off_chain_ticker": "POL_USD" }, { "name": "okx_ws", - "off_chain_ticker": "MATIC-USDT", + "off_chain_ticker": "POL-USDT", "normalize_by_pair": { "Base": "USDT", "Quote": "USD" @@ -3368,7 +3345,7 @@ }, { "params": { - "ticker": "MATIC-USD", + "ticker": "POL-USD", "id": 3, "market_id": 3, "atomic_resolution": -5, @@ -3799,12 +3776,12 @@ "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LINK-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"LINKUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" }, { - "pair": "MATIC-USD", + "pair": "POL-USD", "id": 3, "exponent": -10, "min_exchanges": 3, "min_price_change_ppm": 2500, - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MATIC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"maticusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"MATICUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" + "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" }, { "pair": "CRV-USD", diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index 0007ebff2d..fbe658ac42 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -242,9 +242,9 @@ function edit_genesis() { dasel put -t int -f "$GENESIS" '.app_state.perpetuals.perpetuals.[2].params.liquidity_tier' -v '1' dasel put -t int -f "$GENESIS" '.app_state.perpetuals.perpetuals.[2].params.market_type' -v '1' - # Perpetual: MATIC-USD + # Perpetual: POL-USD dasel put -t json -f "$GENESIS" '.app_state.perpetuals.perpetuals.[]' -v "{}" - dasel put -t string -f "$GENESIS" '.app_state.perpetuals.perpetuals.[3].params.ticker' -v 'MATIC-USD' + dasel put -t string -f "$GENESIS" '.app_state.perpetuals.perpetuals.[3].params.ticker' -v 'POL-USD' dasel put -t int -f "$GENESIS" '.app_state.perpetuals.perpetuals.[3].params.id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.perpetuals.perpetuals.[3].params.market_id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.perpetuals.perpetuals.[3].params.atomic_resolution' -v '-5' @@ -607,26 +607,23 @@ function edit_genesis() { dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.LINK/USD.provider_configs.[]' -v '{"name": "okx_ws", "off_chain_ticker": "LINK-USDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - # Marketmap: MATIC-USD - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD' -v "{}" - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker' -v "{}" + # Marketmap: POL-USD + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD' -v "{}" + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker' -v "{}" - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.currency_pair' -v "{}" - dasel put -t string -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.currency_pair.Base' -v 'MATIC' - dasel put -t string -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.currency_pair.Quote' -v 'USD' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.currency_pair' -v "{}" + dasel put -t string -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.currency_pair.Base' -v 'POL' + dasel put -t string -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.currency_pair.Quote' -v 'USD' - dasel put -t int -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.decimals' -v '10' - dasel put -t int -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.min_provider_count' -v '3' - dasel put -t bool -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.ticker.enabled' -v 'true' + dasel put -t int -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.decimals' -v '10' + dasel put -t int -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.min_provider_count' -v '3' + dasel put -t bool -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.ticker.enabled' -v 'true' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "binance_ws", "off_chain_ticker": "MATICUSDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "bybit_ws", "off_chain_ticker": "MATICUSDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "coinbase_ws", "off_chain_ticker": "MATIC-USD"}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "gate_ws", "off_chain_ticker": "MATIC_USDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "huobi_ws", "off_chain_ticker": "maticusdt", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "kraken_api", "off_chain_ticker": "MATICUSD"}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "kucoin_ws", "off_chain_ticker": "MATIC-USDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' - dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.MATIC/USD.provider_configs.[]' -v '{"name": "okx_ws", "off_chain_ticker": "MATIC-USDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.provider_configs.[]' -v '{"name": "binance_ws", "off_chain_ticker": "POLUSDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.provider_configs.[]' -v '{"name": "bybit_ws", "off_chain_ticker": "POLUSDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.provider_configs.[]' -v '{"name": "coinbase_ws", "off_chain_ticker": "POL-USD"}' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.provider_configs.[]' -v '{"name": "crypto_dot_com_ws", "off_chain_ticker": "POL_USD"}' + dasel put -t json -f "$GENESIS" '.app_state.marketmap.market_map.markets.POL/USD.provider_configs.[]' -v '{"name": "okx_ws", "off_chain_ticker": "POL-USDT", "normalize_by_pair": {"Base": "USDT", "Quote": "USD"}}' # Marketmap: CRV-USD @@ -1322,9 +1319,9 @@ function edit_genesis() { link_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/link_exchange_config.json" | jq -c '.') dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[2].exchange_config_json' -v "$link_exchange_config_json" - # Market: MATIC-USD + # Market: POL-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].pair' -v 'MATIC-USD' + dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].pair' -v 'POL-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].min_exchanges' -v '3' @@ -1332,10 +1329,10 @@ function edit_genesis() { dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].price' -v '6665746387' # $0.6666 = 1 MATIC. - # MATIC Exchange Config - matic_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/matic_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].exchange_config_json' -v "$matic_exchange_config_json" + dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].price' -v '3703925550' # $0.370 = 1 POL. + # POL Exchange Config + pol_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/pol_exchange_config.json" | jq -c '.') + dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].exchange_config_json' -v "$pol_exchange_config_json" # Market: CRV-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" @@ -1898,7 +1895,7 @@ function edit_genesis() { dasel put -t int -f "$GENESIS" '.app_state.clob.clob_pairs.[2].subticks_per_tick' -v '1000000' dasel put -t int -f "$GENESIS" '.app_state.clob.clob_pairs.[2].quantum_conversion_exponent' -v '-9' - # Clob: MATIC-USD + # Clob: POL-USD dasel put -t json -f "$GENESIS" '.app_state.clob.clob_pairs.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.clob.clob_pairs.[3].id' -v '3' dasel put -t string -f "$GENESIS" '.app_state.clob.clob_pairs.[3].status' -v "$INITIAL_CLOB_PAIR_STATUS" diff --git a/protocol/testing/mainnet/genesis.json b/protocol/testing/mainnet/genesis.json index 14a2fc1292..c535a63708 100644 --- a/protocol/testing/mainnet/genesis.json +++ b/protocol/testing/mainnet/genesis.json @@ -2951,7 +2951,7 @@ }, { "params": { - "ticker": "MATIC-USD", + "ticker": "POL-USD", "id": 3, "market_id": 3, "atomic_resolution": -5, @@ -3317,12 +3317,12 @@ "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LINK-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"LINKUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Mexc\",\"ticker\":\"LINK_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" }, { - "pair": "MATIC-USD", + "pair": "POL-USD", "id": 3, "exponent": -10, "min_exchanges": 3, "min_price_change_ppm": 2500, - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MATIC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"maticusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"MATICUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Mexc\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" + "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}" }, { "pair": "CRV-USD", diff --git a/protocol/testing/testnet-dev/dev.sh b/protocol/testing/testnet-dev/dev.sh index 809c543346..91e20a45ff 100755 --- a/protocol/testing/testnet-dev/dev.sh +++ b/protocol/testing/testnet-dev/dev.sh @@ -85,7 +85,7 @@ VAULT_ACCOUNTS=( "dydx1c0m5x87llaunl5sgv3q5vd7j5uha26d2q2r2q0" # BTC vault "dydx14rplxdyycc6wxmgl8fggppgq4774l70zt6phkw" # ETH vault "dydx190te44zcctdgk0qmqtenve2m00g3r2dn7ntd72" # LINK vault - "dydx1a83cjn83vqh5ss2vccg6uuaeky7947xldp9r2e" # MATIC vault + "dydx1a83cjn83vqh5ss2vccg6uuaeky7947xldp9r2e" # POL vault "dydx1nkz8xcar6sxedw0yva6jzjplw7hfg6pp6e7h0l" # CRV vault ) # Number of each vault above, which for CLOB vaults is the ID of the clob pair it quotes on. @@ -93,7 +93,7 @@ VAULT_NUMBERS=( 0 # BTC clob pair ID 1 # ETH clob pair ID 2 # LINK clob pair ID - 3 # MATIC clob pair ID + 3 # POL clob pair ID 4 # CRV clob pair ID ) diff --git a/protocol/testing/testnet-staging/staging.sh b/protocol/testing/testnet-staging/staging.sh index ebd2871f97..57fcbcf4c8 100755 --- a/protocol/testing/testnet-staging/staging.sh +++ b/protocol/testing/testnet-staging/staging.sh @@ -139,7 +139,7 @@ VAULT_ACCOUNTS=( "dydx1c0m5x87llaunl5sgv3q5vd7j5uha26d2q2r2q0" # BTC vault "dydx14rplxdyycc6wxmgl8fggppgq4774l70zt6phkw" # ETH vault "dydx190te44zcctdgk0qmqtenve2m00g3r2dn7ntd72" # LINK vault - "dydx1a83cjn83vqh5ss2vccg6uuaeky7947xldp9r2e" # MATIC vault + "dydx1a83cjn83vqh5ss2vccg6uuaeky7947xldp9r2e" # POL vault "dydx1nkz8xcar6sxedw0yva6jzjplw7hfg6pp6e7h0l" # CRV vault ) # Number of each vault above, which for CLOB vaults is the ID of the clob pair it quotes on. @@ -147,7 +147,7 @@ VAULT_NUMBERS=( 0 # BTC clob pair ID 1 # ETH clob pair ID 2 # LINK clob pair ID - 3 # MATIC clob pair ID + 3 # POL clob pair ID 4 # CRV clob pair ID ) diff --git a/protocol/testing/testnet/genesis.json b/protocol/testing/testnet/genesis.json index 0dad18164a..3fe44a2f9b 100644 --- a/protocol/testing/testnet/genesis.json +++ b/protocol/testing/testnet/genesis.json @@ -5808,7 +5808,7 @@ "id": 3, "liquidity_tier": 1, "market_id": 3, - "ticker": "MATIC-USD" + "ticker": "POL-USD" } }, { @@ -6130,12 +6130,12 @@ "pair": "LINK-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"MATICUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MATIC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"maticusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"MATICUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Mexc\",\"ticker\":\"MATIC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MATIC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", + "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 3, "min_exchanges": 3, "min_price_change_ppm": 2500, - "pair": "MATIC-USD" + "pair": "POL-USD" }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"CRVUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"CRV-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"CRV_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"CRVUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Mexc\",\"ticker\":\"CRV_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", diff --git a/protocol/testutil/constants/genesis.go b/protocol/testutil/constants/genesis.go index 7c78b3a6ee..b2cdbb41ae 100644 --- a/protocol/testutil/constants/genesis.go +++ b/protocol/testutil/constants/genesis.go @@ -2557,83 +2557,6 @@ const GenesisState = `{ } ] }, - "MATIC/USD": { - "ticker": { - "currency_pair": { - "Base": "MATIC", - "Quote": "USD" - }, - "decimals": 10, - "min_provider_count": 3, - "enabled": true - }, - "provider_configs": [ - { - "name": "binance_ws", - "off_chain_ticker": "MATICUSDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "bybit_ws", - "off_chain_ticker": "MATICUSDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "coinbase_ws", - "off_chain_ticker": "MATIC-USD" - }, - { - "name": "gate_ws", - "off_chain_ticker": "MATIC_USDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "huobi_ws", - "off_chain_ticker": "maticusdt", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "kraken_api", - "off_chain_ticker": "MATICUSD" - }, - { - "name": "kucoin_ws", - "off_chain_ticker": "MATIC-USDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "mexc_ws", - "off_chain_ticker": "MATICUSDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - }, - { - "name": "okx_ws", - "off_chain_ticker": "MATIC-USDT", - "normalize_by_pair": { - "Base": "USDT", - "Quote": "USD" - } - } - ] - }, "MKR/USD": { "ticker": { "currency_pair": { @@ -2874,6 +2797,51 @@ const GenesisState = `{ } ] }, + "POL/USD": { + "ticker": { + "currency_pair": { + "Base": "POL", + "Quote": "USD" + }, + "decimals": 10, + "min_provider_count": 3, + "enabled": true + }, + "provider_configs": [ + { + "name": "binance_ws", + "off_chain_ticker": "POLUSDT", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + } + }, + { + "name": "bybit_ws", + "off_chain_ticker": "POLUSDT", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + } + }, + { + "name": "coinbase_ws", + "off_chain_ticker": "POL-USD" + }, + { + "name": "crypto_dot_com_ws", + "off_chain_ticker": "POL_USD" + }, + { + "name": "okx_ws", + "off_chain_ticker": "POL-USDT", + "normalize_by_pair": { + "Base": "USDT", + "Quote": "USD" + } + } + ] + }, "SEI/USD": { "ticker": { "currency_pair": { @@ -4022,12 +3990,12 @@ const GenesisState = `{ "pair": "LINK-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"MATICUSDT\\\"\"},{\"exchangeName\":\"BinanceUS\",\"ticker\":\"\\\"MATICUSD\\\"\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MATIC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"MATIC_USDT\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"maticusdt\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MATIC-USDT\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MATIC-USDT\"}]}", + "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 3, "min_exchanges": 1, "min_price_change_ppm": 2000, - "pair": "MATIC-USD" + "pair": "POL-USD" }, { "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"CRVUSDT\\\"\"},{\"exchangeName\":\"BinanceUS\",\"ticker\":\"\\\"CRVUSD\\\"\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"CRVUSDT\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"CRV-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"CRV_USDT\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"crvusdt\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"CRVUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"CRV-USDT\"},{\"exchangeName\":\"Okx\",\"ticker\":\"CRV-USDT\"}]}", diff --git a/protocol/testutil/constants/pricefeed.go b/protocol/testutil/constants/pricefeed.go index f7bdf0e2c2..08ed480a3d 100644 --- a/protocol/testutil/constants/pricefeed.go +++ b/protocol/testutil/constants/pricefeed.go @@ -658,8 +658,8 @@ var ( }, { Id: MarketId11, - Pair: MaticUsdPair, - Exponent: MaticUsdExponent, + Pair: PolUsdPair, + Exponent: PolUsdExponent, MinExchanges: 1, }, } @@ -684,7 +684,7 @@ var ( MarketId8: EthUsdExponent, MarketId9: LtcUsdExponent, MarketId10: SolUsdExponent, - MarketId11: MaticUsdExponent, + MarketId11: PolUsdExponent, } TestExchangeQueryConfigs = map[string]*daemonClientTypes.ExchangeQueryConfig{ diff --git a/protocol/testutil/constants/prices.go b/protocol/testutil/constants/prices.go index 89c7ee360f..59c47ea5fc 100644 --- a/protocol/testutil/constants/prices.go +++ b/protocol/testutil/constants/prices.go @@ -21,23 +21,23 @@ func init() { } const ( - BtcUsdPair = "BTC-USD" - EthUsdPair = "ETH-USD" - MaticUsdPair = "MATIC-USD" - SolUsdPair = "SOL-USD" - LtcUsdPair = "LTC-USD" - IsoUsdPair = "ISO-USD" - Iso2UsdPair = "ISO2-USD" + BtcUsdPair = "BTC-USD" + EthUsdPair = "ETH-USD" + PolUsdPair = "POL-USD" + SolUsdPair = "SOL-USD" + LtcUsdPair = "LTC-USD" + IsoUsdPair = "ISO-USD" + Iso2UsdPair = "ISO2-USD" - BtcUsdExponent = -5 - EthUsdExponent = -6 - LinkUsdExponent = -8 - MaticUsdExponent = -9 - CrvUsdExponent = -10 - SolUsdExponent = -8 - LtcUsdExponent = -7 - IsoUsdExponent = -8 - Iso2UsdExponent = -7 + BtcUsdExponent = -5 + EthUsdExponent = -6 + LinkUsdExponent = -8 + PolUsdExponent = -9 + CrvUsdExponent = -10 + SolUsdExponent = -8 + LtcUsdExponent = -7 + IsoUsdExponent = -8 + Iso2UsdExponent = -7 CoinbaseExchangeName = "Coinbase" BinanceExchangeName = "Binance" diff --git a/protocol/testutil/daemons/pricefeed/exchange_config/market_id.go b/protocol/testutil/daemons/pricefeed/exchange_config/market_id.go index cb6fe6c4d6..9d8e0696b7 100644 --- a/protocol/testutil/daemons/pricefeed/exchange_config/market_id.go +++ b/protocol/testutil/daemons/pricefeed/exchange_config/market_id.go @@ -10,8 +10,8 @@ const ( MARKET_ETH_USD types.MarketId = 1 // MARKET_LINK_USD is the id for the LINK-USD market pair. MARKET_LINK_USD types.MarketId = 2 - // MARKET_MATIC_USD is the id for the MATIC-USD market pair. - MARKET_MATIC_USD types.MarketId = 3 + // MARKET_POL_USD is the id for the POL-USD market pair. + MARKET_POL_USD types.MarketId = 3 // MARKET_CRV_USD is the id for the CRV-USD market pair. MARKET_CRV_USD types.MarketId = 4 // MARKET_SOL_USD is the id for the SOL-USD market pair. diff --git a/protocol/testutil/daemons/pricefeed/exchange_config/static_market_names.go b/protocol/testutil/daemons/pricefeed/exchange_config/static_market_names.go index 6a27151ec2..77b706eb6e 100644 --- a/protocol/testutil/daemons/pricefeed/exchange_config/static_market_names.go +++ b/protocol/testutil/daemons/pricefeed/exchange_config/static_market_names.go @@ -8,39 +8,39 @@ var ( // StaticMarketNames maps marketIds to their human-readable market names. This list is // used for generating market exchange config that is then read back into the daemon. StaticMarketNames = map[types.MarketId]string{ - MARKET_BTC_USD: "BTC-USD", - MARKET_ETH_USD: "ETH-USD", - MARKET_LINK_USD: "LINK-USD", - MARKET_MATIC_USD: "MATIC-USD", - MARKET_CRV_USD: "CRV-USD", - MARKET_SOL_USD: "SOL-USD", - MARKET_ADA_USD: "ADA-USD", - MARKET_AVAX_USD: "AVAX-USD", - MARKET_FIL_USD: "FIL-USD", - MARKET_LTC_USD: "LTC-USD", - MARKET_DOGE_USD: "DOGE-USD", - MARKET_ATOM_USD: "ATOM-USD", - MARKET_DOT_USD: "DOT-USD", - MARKET_UNI_USD: "UNI-USD", - MARKET_BCH_USD: "BCH-USD", - MARKET_TRX_USD: "TRX-USD", - MARKET_NEAR_USD: "NEAR-USD", - MARKET_MKR_USD: "MKR-USD", - MARKET_XLM_USD: "XLM-USD", - MARKET_ETC_USD: "ETC-USD", - MARKET_COMP_USD: "COMP-USD", - MARKET_WLD_USD: "WLD-USD", - MARKET_APE_USD: "APE-USD", - MARKET_APT_USD: "APT-USD", - MARKET_ARB_USD: "ARB-USD", - MARKET_BLUR_USD: "BLUR-USD", - MARKET_LDO_USD: "LDO-USD", - MARKET_OP_USD: "OP-USD", - MARKET_PEPE_USD: "PEPE-USD", - MARKET_SEI_USD: "SEI-USD", - MARKET_SHIB_USD: "SHIB-USD", - MARKET_SUI_USD: "SUI-USD", - MARKET_XRP_USD: "XRP-USD", - MARKET_USDT_USD: "USDT-USD", + MARKET_BTC_USD: "BTC-USD", + MARKET_ETH_USD: "ETH-USD", + MARKET_LINK_USD: "LINK-USD", + MARKET_POL_USD: "POL-USD", + MARKET_CRV_USD: "CRV-USD", + MARKET_SOL_USD: "SOL-USD", + MARKET_ADA_USD: "ADA-USD", + MARKET_AVAX_USD: "AVAX-USD", + MARKET_FIL_USD: "FIL-USD", + MARKET_LTC_USD: "LTC-USD", + MARKET_DOGE_USD: "DOGE-USD", + MARKET_ATOM_USD: "ATOM-USD", + MARKET_DOT_USD: "DOT-USD", + MARKET_UNI_USD: "UNI-USD", + MARKET_BCH_USD: "BCH-USD", + MARKET_TRX_USD: "TRX-USD", + MARKET_NEAR_USD: "NEAR-USD", + MARKET_MKR_USD: "MKR-USD", + MARKET_XLM_USD: "XLM-USD", + MARKET_ETC_USD: "ETC-USD", + MARKET_COMP_USD: "COMP-USD", + MARKET_WLD_USD: "WLD-USD", + MARKET_APE_USD: "APE-USD", + MARKET_APT_USD: "APT-USD", + MARKET_ARB_USD: "ARB-USD", + MARKET_BLUR_USD: "BLUR-USD", + MARKET_LDO_USD: "LDO-USD", + MARKET_OP_USD: "OP-USD", + MARKET_PEPE_USD: "PEPE-USD", + MARKET_SEI_USD: "SEI-USD", + MARKET_SHIB_USD: "SHIB-USD", + MARKET_SUI_USD: "SUI-USD", + MARKET_XRP_USD: "XRP-USD", + MARKET_USDT_USD: "USDT-USD", } ) diff --git a/protocol/testutil/daemons/pricefeed/exchange_config/testnet_exchange_market_config.go b/protocol/testutil/daemons/pricefeed/exchange_config/testnet_exchange_market_config.go index 8ab6dc9ee5..b785ae00bf 100644 --- a/protocol/testutil/daemons/pricefeed/exchange_config/testnet_exchange_market_config.go +++ b/protocol/testutil/daemons/pricefeed/exchange_config/testnet_exchange_market_config.go @@ -30,8 +30,8 @@ var ( Ticker: "LINKUSDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, - MARKET_MATIC_USD: { - Ticker: "MATICUSDT", + MARKET_POL_USD: { + Ticker: "POLUSDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, MARKET_CRV_USD: { @@ -224,9 +224,6 @@ var ( MARKET_USDT_USD: { Ticker: "USDTZUSD", }, - MARKET_MATIC_USD: { - Ticker: "MATICUSD", - }, MARKET_MKR_USD: { Ticker: "MKRUSD", }, @@ -242,10 +239,6 @@ var ( Ticker: "DYDX_USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, - MARKET_MATIC_USD: { - Ticker: "MATIC_USDT", - AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), - }, MARKET_CRV_USD: { Ticker: "CRV_USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), @@ -443,8 +436,8 @@ var ( Ticker: "DOTUSDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, - MARKET_MATIC_USD: { - Ticker: "MATICUSDT", + MARKET_POL_USD: { + Ticker: "POLUSDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, MARKET_USDT_USD: { @@ -454,16 +447,16 @@ var ( }, }, exchange_common.EXCHANGE_ID_CRYPTO_COM: { - Id: exchange_common.EXCHANGE_ID_CRYPTO_COM, - MarketToMarketConfig: map[types.MarketId]types.MarketConfig{}, + Id: exchange_common.EXCHANGE_ID_CRYPTO_COM, + MarketToMarketConfig: map[types.MarketId]types.MarketConfig{ + MARKET_POL_USD: { + Ticker: "POL_USD", + }, + }, }, exchange_common.EXCHANGE_ID_HUOBI: { Id: exchange_common.EXCHANGE_ID_HUOBI, MarketToMarketConfig: map[types.MarketId]types.MarketConfig{ - MARKET_MATIC_USD: { - Ticker: "maticusdt", - AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), - }, MARKET_SOL_USD: { Ticker: "solusdt", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), @@ -554,10 +547,6 @@ var ( Ticker: "LINK-USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, - MARKET_MATIC_USD: { - Ticker: "MATIC-USDT", - AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), - }, MARKET_CRV_USD: { Ticker: "CRV-USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), @@ -700,8 +689,8 @@ var ( Ticker: "LINK-USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, - MARKET_MATIC_USD: { - Ticker: "MATIC-USDT", + MARKET_POL_USD: { + Ticker: "POL-USDT", AdjustByMarket: newMarketIdWithValue(MARKET_USDT_USD), }, MARKET_CRV_USD: { @@ -834,8 +823,8 @@ var ( MARKET_LINK_USD: { Ticker: "LINK-USD", }, - MARKET_MATIC_USD: { - Ticker: "MATIC-USD", + MARKET_POL_USD: { + Ticker: "POL-USD", }, MARKET_CRV_USD: { Ticker: "CRV-USD", From 51bd87f4c40eee6bc7c422e7ccfac914fca68cd1 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:01:00 -0600 Subject: [PATCH 090/120] [TRA-721] Enforce sidecar versions (#2491) --- protocol/app/app.go | 1 + protocol/daemons/slinky/client/client.go | 67 ++++++++++++++--- protocol/daemons/slinky/client/client_test.go | 12 +++- protocol/daemons/slinky/client/constants.go | 9 ++- .../slinky/client/sidecar_version_checker.go | 72 +++++++++++++++++++ .../client/sidecar_version_checker_test.go | 62 ++++++++++++++++ protocol/go.mod | 2 +- protocol/mocks/Makefile | 3 +- protocol/mocks/SidecarVersionChecker.go | 69 ++++++++++++++++++ 9 files changed, 281 insertions(+), 16 deletions(-) create mode 100644 protocol/daemons/slinky/client/sidecar_version_checker.go create mode 100644 protocol/daemons/slinky/client/sidecar_version_checker_test.go create mode 100644 protocol/mocks/SidecarVersionChecker.go diff --git a/protocol/app/app.go b/protocol/app/app.go index 4e974025f4..c0518c81f0 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -888,6 +888,7 @@ func New( ) app.RegisterDaemonWithHealthMonitor(app.SlinkyClient.GetMarketPairHC(), maxDaemonUnhealthyDuration) app.RegisterDaemonWithHealthMonitor(app.SlinkyClient.GetPriceHC(), maxDaemonUnhealthyDuration) + app.RegisterDaemonWithHealthMonitor(app.SlinkyClient.GetSidecarVersionHC(), maxDaemonUnhealthyDuration) } } diff --git a/protocol/daemons/slinky/client/client.go b/protocol/daemons/slinky/client/client.go index 1d02337002..08aa04c467 100644 --- a/protocol/daemons/slinky/client/client.go +++ b/protocol/daemons/slinky/client/client.go @@ -20,14 +20,16 @@ import ( // Client is the daemon implementation for pulling price data from the slinky sidecar. type Client struct { - ctx context.Context - cf context.CancelFunc - marketPairFetcher MarketPairFetcher - marketPairHC daemontypes.HealthCheckable - priceFetcher PriceFetcher - priceHC daemontypes.HealthCheckable - wg sync.WaitGroup - logger log.Logger + ctx context.Context + cf context.CancelFunc + marketPairFetcher MarketPairFetcher + marketPairHC daemontypes.HealthCheckable + priceFetcher PriceFetcher + priceHC daemontypes.HealthCheckable + sidecarVersionChecker SidecarVersionChecker + sidecarVersionHC daemontypes.HealthCheckable + wg sync.WaitGroup + logger log.Logger } func newClient(ctx context.Context, logger log.Logger) *Client { @@ -43,6 +45,11 @@ func newClient(ctx context.Context, logger log.Logger) *Client { &libtime.TimeProviderImpl{}, logger, ), + sidecarVersionHC: daemontypes.NewTimeBoundedHealthCheckable( + SlinkyClientSidecarVersionFetcherDaemonModuleName, + &libtime.TimeProviderImpl{}, + logger, + ), logger: logger, } client.ctx, client.cf = context.WithCancel(ctx) @@ -57,6 +64,10 @@ func (c *Client) GetPriceHC() daemontypes.HealthCheckable { return c.priceHC } +func (c *Client) GetSidecarVersionHC() daemontypes.HealthCheckable { + return c.sidecarVersionHC +} + // start creates the main goroutines of the Client. func (c *Client) start( slinky oracleclient.OracleClient, @@ -71,6 +82,7 @@ func (c *Client) start( defer c.wg.Done() c.RunMarketPairFetcher(c.ctx, appFlags, grpcClient) }() + // 2. Start the PriceFetcher c.priceFetcher = NewPriceFetcher( c.marketPairFetcher, @@ -83,6 +95,17 @@ func (c *Client) start( defer c.wg.Done() c.RunPriceFetcher(c.ctx) }() + + // 3. Start the SidecarVersionChecker + c.sidecarVersionChecker = NewSidecarVersionChecker( + slinky, + c.logger, + ) + c.wg.Add(1) + go func() { + defer c.wg.Done() + c.RunSidecarVersionChecker(c.ctx) + }() return nil } @@ -146,8 +169,34 @@ func (c *Client) RunMarketPairFetcher(ctx context.Context, appFlags appflags.Fla } } +// RunSidecarVersionChecker periodically calls the sidecarVersionChecker to check if the running sidecar version +// is at least a minimum acceptable version. +func (c *Client) RunSidecarVersionChecker(ctx context.Context) { + err := c.sidecarVersionChecker.Start(ctx) + if err != nil { + c.logger.Error("Error initializing sidecarVersionChecker in slinky daemon", "error", err) + panic(err) + } + ticker := time.NewTicker(SlinkySidecarCheckDelay) + defer ticker.Stop() + for { + select { + case <-ticker.C: + err = c.sidecarVersionChecker.CheckSidecarVersion(ctx) + if err != nil { + c.logger.Error("Sidecar version check failed", "error", err) + c.sidecarVersionHC.ReportFailure(errors.Wrap(err, "Sidecar version check failed for slinky daemon")) + } else { + c.sidecarVersionHC.ReportSuccess() + } + case <-ctx.Done(): + return + } + } +} + // StartNewClient creates and runs a Client. -// The client creates the MarketPairFetcher and PriceFetcher, +// The client creates the MarketPairFetcher, PriceFetcher, and SidecarVersionChecker, // connects to the required grpc services, and launches them in goroutines. // It is non-blocking and returns on successful startup. // If it hits a critical error in startup it panics. diff --git a/protocol/daemons/slinky/client/client_test.go b/protocol/daemons/slinky/client/client_test.go index a256619b98..8c6d439321 100644 --- a/protocol/daemons/slinky/client/client_test.go +++ b/protocol/daemons/slinky/client/client_test.go @@ -52,7 +52,7 @@ func TestClient(t *testing.T) { }() slinky.On("Stop").Return(nil) - slinky.On("Start", mock.Anything).Return(nil).Once() + slinky.On("Start", mock.Anything).Return(nil).Twice() slinky.On("Prices", mock.Anything, mock.Anything). Return(&types.QueryPricesResponse{ Prices: map[string]string{ @@ -60,8 +60,14 @@ func TestClient(t *testing.T) { }, Timestamp: time.Now(), }, nil) + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: client.MinSidecarVersion, + }, nil) + client.SlinkyPriceFetchDelay = time.Millisecond client.SlinkyMarketParamFetchDelay = time.Millisecond + client.SlinkySidecarCheckDelay = time.Millisecond cli = client.StartNewClient( context.Background(), slinky, @@ -73,7 +79,9 @@ func TestClient(t *testing.T) { ) waitTime := time.Second * 5 require.Eventually(t, func() bool { - return cli.GetMarketPairHC().HealthCheck() == nil && cli.GetPriceHC().HealthCheck() == nil + return cli.GetMarketPairHC().HealthCheck() == nil && + cli.GetPriceHC().HealthCheck() == nil && + cli.GetSidecarVersionHC().HealthCheck() == nil }, waitTime, time.Millisecond*500, "Slinky daemon failed to become healthy within %s", waitTime) cli.Stop() } diff --git a/protocol/daemons/slinky/client/constants.go b/protocol/daemons/slinky/client/constants.go index aa711e69b9..e563b66197 100644 --- a/protocol/daemons/slinky/client/constants.go +++ b/protocol/daemons/slinky/client/constants.go @@ -12,11 +12,14 @@ var ( // SlinkyMarketParamFetchDelay is the frequency at which we query the x/price module to refresh mappings from // currency pair to x/price ID. SlinkyMarketParamFetchDelay = time.Millisecond * 1900 + SlinkySidecarCheckDelay = time.Second * 60 ) const ( // SlinkyClientDaemonModuleName is the module name used in logging. - SlinkyClientDaemonModuleName = "slinky-client-daemon" - SlinkyClientPriceFetcherDaemonModuleName = "slinky-client-price-fetcher-daemon" - SlinkyClientMarketPairFetcherDaemonModuleName = "slinky-client-market-pair-fetcher-daemon" + SlinkyClientDaemonModuleName = "slinky-client-daemon" + SlinkyClientPriceFetcherDaemonModuleName = "slinky-client-price-fetcher-daemon" + SlinkyClientMarketPairFetcherDaemonModuleName = "slinky-client-market-pair-fetcher-daemon" + SlinkyClientSidecarVersionFetcherDaemonModuleName = "slinky-client-sidecar-version-fetcher-daemon" + MinSidecarVersion = "v1.0.12" ) diff --git a/protocol/daemons/slinky/client/sidecar_version_checker.go b/protocol/daemons/slinky/client/sidecar_version_checker.go new file mode 100644 index 0000000000..af7ec97199 --- /dev/null +++ b/protocol/daemons/slinky/client/sidecar_version_checker.go @@ -0,0 +1,72 @@ +package client + +import ( + "context" + "fmt" + + "cosmossdk.io/log" + "github.com/hashicorp/go-version" + + oracleclient "github.com/skip-mev/connect/v2/service/clients/oracle" + "github.com/skip-mev/connect/v2/service/servers/oracle/types" +) + +// SidecarVersionChecker is a lightweight process run in a goroutine by the slinky client. +// Its purpose is to query the running sidecar version and check if it is at least a minimum +// acceptable version. +type SidecarVersionChecker interface { + Start(ctx context.Context) error + Stop() + CheckSidecarVersion(context.Context) error +} + +// SidecarVersionCheckerImpl implements the SidecarVersionChecker interface. +type SidecarVersionCheckerImpl struct { + slinky oracleclient.OracleClient + logger log.Logger +} + +func NewSidecarVersionChecker(slinky oracleclient.OracleClient, logger log.Logger) SidecarVersionChecker { + return &SidecarVersionCheckerImpl{ + slinky: slinky, + logger: logger, + } +} + +// Start initializes the underlying connections of the SidecarVersionChecker. +func (s *SidecarVersionCheckerImpl) Start( + ctx context.Context) error { + return s.slinky.Start(ctx) +} + +// Stop closes all existing connections. +func (s *SidecarVersionCheckerImpl) Stop() { + _ = s.slinky.Stop() +} + +func (s *SidecarVersionCheckerImpl) CheckSidecarVersion(ctx context.Context) error { + // Retrieve sidecar version via gRPC + slinkyResponse, err := s.slinky.Version(ctx, &types.QueryVersionRequest{}) + if err != nil { + return err + } + current, err := version.NewVersion(slinkyResponse.Version) + if err != nil { + return fmt.Errorf("failed to parse current version: %w", err) + } + + minimum, err := version.NewVersion(MinSidecarVersion) + if err != nil { + return fmt.Errorf("failed to parse minimum version: %w", err) + } + + // Compare versions + if current.LessThan(minimum) { + return fmt.Errorf("Sidecar version %s is less than minimum required version %s. "+ + "The node will shut down soon", current, minimum) + } + + // Version is acceptable + s.logger.Info("Sidecar version check passed", "version", current) + return nil +} diff --git a/protocol/daemons/slinky/client/sidecar_version_checker_test.go b/protocol/daemons/slinky/client/sidecar_version_checker_test.go new file mode 100644 index 0000000000..97dd6b6839 --- /dev/null +++ b/protocol/daemons/slinky/client/sidecar_version_checker_test.go @@ -0,0 +1,62 @@ +package client_test + +import ( + "context" + "testing" + + "cosmossdk.io/log" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/dydxprotocol/v4-chain/protocol/daemons/slinky/client" + "github.com/dydxprotocol/v4-chain/protocol/mocks" + "github.com/skip-mev/connect/v2/service/servers/oracle/types" +) + +func TestSidecarVersionChecker(t *testing.T) { + logger := log.NewTestLogger(t) + var fetcher client.SidecarVersionChecker + + t.Run("Checks sidecar version passes", func(t *testing.T) { + slinky := mocks.NewOracleClient(t) + slinky.On("Stop").Return(nil) + slinky.On("Start", mock.Anything).Return(nil).Once() + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: client.MinSidecarVersion, + }, nil) + fetcher = client.NewSidecarVersionChecker(slinky, logger) + require.NoError(t, fetcher.Start(context.Background())) + require.NoError(t, fetcher.CheckSidecarVersion(context.Background())) + fetcher.Stop() + }) + + t.Run("Checks sidecar version less than minimum version", func(t *testing.T) { + slinky := mocks.NewOracleClient(t) + slinky.On("Stop").Return(nil) + slinky.On("Start", mock.Anything).Return(nil).Once() + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: "v0.0.0", + }, nil) + fetcher = client.NewSidecarVersionChecker(slinky, logger) + require.NoError(t, fetcher.Start(context.Background())) + require.ErrorContains(t, fetcher.CheckSidecarVersion(context.Background()), + "Sidecar version 0.0.0 is less than minimum required version") + fetcher.Stop() + }) + + t.Run("Checks sidecar version incorrectly formatted", func(t *testing.T) { + slinky := mocks.NewOracleClient(t) + slinky.On("Stop").Return(nil) + slinky.On("Start", mock.Anything).Return(nil).Once() + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: "a.b.c", + }, nil) + fetcher = client.NewSidecarVersionChecker(slinky, logger) + require.NoError(t, fetcher.Start(context.Background())) + require.ErrorContains(t, fetcher.CheckSidecarVersion(context.Background()), "Malformed version: a.b.c") + fetcher.Stop() + }) +} diff --git a/protocol/go.mod b/protocol/go.mod index 2af0fc5601..1d940dd105 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -62,6 +62,7 @@ require ( github.com/go-kit/log v0.2.1 github.com/gorilla/websocket v1.5.3 github.com/hashicorp/go-metrics v0.5.3 + github.com/hashicorp/go-version v1.7.0 github.com/ory/dockertest/v3 v3.10.0 github.com/pelletier/go-toml v1.9.5 github.com/rs/zerolog v1.33.0 @@ -257,7 +258,6 @@ require ( github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect diff --git a/protocol/mocks/Makefile b/protocol/mocks/Makefile index dc0fda979d..33ef2f48fa 100644 --- a/protocol/mocks/Makefile +++ b/protocol/mocks/Makefile @@ -60,7 +60,8 @@ mock-gen: @go run github.com/vektra/mockery/v2 --name=PriceUpdateGenerator --dir=./app/prepare/prices --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=PriceFetcher --dir=./daemons/slinky/client --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=MarketPairFetcher --dir=./daemons/slinky/client --recursive --output=./mocks + @go run github.com/vektra/mockery/v2 --name=SidecarVersionChecker --dir=./daemons/slinky/client --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=OracleClient --dir=$(GOPATH)/pkg/mod/github.com/skip-mev/connect/v2@$(CONNECT_VERSION)/service/clients/oracle --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=ExtendVoteHandler --dir=$(GOPATH)/pkg/mod/github.com/dydxprotocol/cosmos-sdk@$(COSMOS_VERSION)/types --recursive --output=./mocks @go run github.com/vektra/mockery/v2 --name=UpdateMarketPriceTxDecoder --dir=./app/process --recursive --output=./mocks - @go run github.com/vektra/mockery/v2 --name=AssetsKeeper --dir=./x//types --recursive --output=./mocks + @go run github.com/vektra/mockery/v2 --name=AssetsKeeper --dir=./x/assets/types --recursive --output=./mocks diff --git a/protocol/mocks/SidecarVersionChecker.go b/protocol/mocks/SidecarVersionChecker.go new file mode 100644 index 0000000000..2719f588fe --- /dev/null +++ b/protocol/mocks/SidecarVersionChecker.go @@ -0,0 +1,69 @@ +// Code generated by mockery v2.46.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// SidecarVersionChecker is an autogenerated mock type for the SidecarVersionChecker type +type SidecarVersionChecker struct { + mock.Mock +} + +// CheckSidecarVersion provides a mock function with given fields: _a0 +func (_m *SidecarVersionChecker) CheckSidecarVersion(_a0 context.Context) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for CheckSidecarVersion") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Start provides a mock function with given fields: ctx +func (_m *SidecarVersionChecker) Start(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Start") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Stop provides a mock function with given fields: +func (_m *SidecarVersionChecker) Stop() { + _m.Called() +} + +// NewSidecarVersionChecker creates a new instance of SidecarVersionChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSidecarVersionChecker(t interface { + mock.TestingT + Cleanup(func()) +}) *SidecarVersionChecker { + mock := &SidecarVersionChecker{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From dea1f2395496901192f5100b92e822ad4c855fa5 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Fri, 18 Oct 2024 11:10:31 -0400 Subject: [PATCH 091/120] Drop patch number from upgrade name, v7.0.0 to v7.0 (#2512) --- protocol/app/upgrades.go | 12 ++++++------ protocol/app/upgrades/{v7.0.0 => v7.0}/constants.go | 4 ++-- protocol/app/upgrades/{v7.0.0 => v7.0}/upgrade.go | 2 +- .../{v7.0.0 => v7.0}/upgrade_container_test.go | 6 +++--- protocol/testing/version/VERSION_CURRENT | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) rename protocol/app/upgrades/{v7.0.0 => v7.0}/constants.go (89%) rename protocol/app/upgrades/{v7.0.0 => v7.0}/upgrade.go (99%) rename protocol/app/upgrades/{v7.0.0 => v7.0}/upgrade_container_test.go (97%) diff --git a/protocol/app/upgrades.go b/protocol/app/upgrades.go index 8c16de0aab..207a5ba815 100644 --- a/protocol/app/upgrades.go +++ b/protocol/app/upgrades.go @@ -3,7 +3,7 @@ package app import ( "fmt" - v7_0_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v7.0.0" + v7_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v7.0" upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,7 +14,7 @@ var ( // `Upgrades` defines the upgrade handlers and store loaders for the application. // New upgrades should be added to this slice after they are implemented. Upgrades = []upgrades.Upgrade{ - v7_0_0.Upgrade, + v7_0.Upgrade, } Forks = []upgrades.Fork{} ) @@ -22,12 +22,12 @@ var ( // setupUpgradeHandlers registers the upgrade handlers to perform custom upgrade // logic and state migrations for software upgrades. func (app *App) setupUpgradeHandlers() { - if app.UpgradeKeeper.HasHandler(v7_0_0.UpgradeName) { - panic(fmt.Sprintf("Cannot register duplicate upgrade handler '%s'", v7_0_0.UpgradeName)) + if app.UpgradeKeeper.HasHandler(v7_0.UpgradeName) { + panic(fmt.Sprintf("Cannot register duplicate upgrade handler '%s'", v7_0.UpgradeName)) } app.UpgradeKeeper.SetUpgradeHandler( - v7_0_0.UpgradeName, - v7_0_0.CreateUpgradeHandler( + v7_0.UpgradeName, + v7_0.CreateUpgradeHandler( app.ModuleManager, app.configurator, app.AccountKeeper, diff --git a/protocol/app/upgrades/v7.0.0/constants.go b/protocol/app/upgrades/v7.0/constants.go similarity index 89% rename from protocol/app/upgrades/v7.0.0/constants.go rename to protocol/app/upgrades/v7.0/constants.go index 505ecf220c..6fa36c8276 100644 --- a/protocol/app/upgrades/v7.0.0/constants.go +++ b/protocol/app/upgrades/v7.0/constants.go @@ -1,4 +1,4 @@ -package v_7_0_0 +package v_7_0 import ( store "cosmossdk.io/store/types" @@ -7,7 +7,7 @@ import ( ) const ( - UpgradeName = "v7.0.0" + UpgradeName = "v7.0" ) var Upgrade = upgrades.Upgrade{ diff --git a/protocol/app/upgrades/v7.0.0/upgrade.go b/protocol/app/upgrades/v7.0/upgrade.go similarity index 99% rename from protocol/app/upgrades/v7.0.0/upgrade.go rename to protocol/app/upgrades/v7.0/upgrade.go index dbf8f5644c..0c520e8177 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade.go +++ b/protocol/app/upgrades/v7.0/upgrade.go @@ -1,4 +1,4 @@ -package v_7_0_0 +package v_7_0 import ( "context" diff --git a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go b/protocol/app/upgrades/v7.0/upgrade_container_test.go similarity index 97% rename from protocol/app/upgrades/v7.0.0/upgrade_container_test.go rename to protocol/app/upgrades/v7.0/upgrade_container_test.go index 069c647b19..d65a77d568 100644 --- a/protocol/app/upgrades/v7.0.0/upgrade_container_test.go +++ b/protocol/app/upgrades/v7.0/upgrade_container_test.go @@ -1,6 +1,6 @@ //go:build all || container_test -package v_7_0_0_test +package v_7_0_test import ( "math/big" @@ -11,7 +11,7 @@ import ( "github.com/cosmos/gogoproto/proto" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - v_7_0_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v7.0.0" + v_7_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v7.0" "github.com/dydxprotocol/v4-chain/protocol/dtypes" "github.com/dydxprotocol/v4-chain/protocol/testing/containertest" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" @@ -38,7 +38,7 @@ func TestStateUpgrade(t *testing.T) { preUpgradeSetups(node, t) preUpgradeChecks(node, t) - err = containertest.UpgradeTestnet(nodeAddress, t, node, v_7_0_0.UpgradeName) + err = containertest.UpgradeTestnet(nodeAddress, t, node, v_7_0.UpgradeName) require.NoError(t, err) postUpgradeChecks(node, t) diff --git a/protocol/testing/version/VERSION_CURRENT b/protocol/testing/version/VERSION_CURRENT index 52b9e4083c..5593dc1fd4 100644 --- a/protocol/testing/version/VERSION_CURRENT +++ b/protocol/testing/version/VERSION_CURRENT @@ -1 +1 @@ -v7.0.0 \ No newline at end of file +v7.0 \ No newline at end of file From 518bab3d66daf16895e01fe7ba81a7b99ca5a903 Mon Sep 17 00:00:00 2001 From: Jonathan Fung <121899091+jonfung-dydx@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:42:05 -0400 Subject: [PATCH 092/120] FNS polish - metrics, max msg size, default flag values (#2517) --- protocol/app/flags/flags.go | 4 +-- protocol/app/flags/flags_test.go | 16 +++++----- protocol/lib/metrics/metric_keys.go | 4 +-- .../streaming/full_node_streaming_manager.go | 31 +++++++++++++++---- protocol/streaming/ws/websocket_server.go | 3 ++ 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/protocol/app/flags/flags.go b/protocol/app/flags/flags.go index aadc805696..b166f88352 100644 --- a/protocol/app/flags/flags.go +++ b/protocol/app/flags/flags.go @@ -72,8 +72,8 @@ const ( DefaultGrpcStreamingEnabled = false DefaultGrpcStreamingFlushIntervalMs = 50 - DefaultGrpcStreamingMaxBatchSize = 2000 - DefaultGrpcStreamingMaxChannelBufferSize = 2000 + DefaultGrpcStreamingMaxBatchSize = 10000 + DefaultGrpcStreamingMaxChannelBufferSize = 10000 DefaultWebsocketStreamingEnabled = false DefaultWebsocketStreamingPort = 9092 DefaultFullNodeStreamingSnapshotInterval = 0 diff --git a/protocol/app/flags/flags_test.go b/protocol/app/flags/flags_test.go index 0ad03872fa..8b3ed1a8f4 100644 --- a/protocol/app/flags/flags_test.go +++ b/protocol/app/flags/flags_test.go @@ -89,8 +89,8 @@ func TestValidate(t *testing.T) { GrpcEnable: true, GrpcStreamingEnabled: true, GrpcStreamingFlushIntervalMs: 100, - GrpcStreamingMaxBatchSize: 2000, - GrpcStreamingMaxChannelBufferSize: 2000, + GrpcStreamingMaxBatchSize: 10000, + GrpcStreamingMaxChannelBufferSize: 10000, WebsocketStreamingEnabled: false, }, }, @@ -100,8 +100,8 @@ func TestValidate(t *testing.T) { GrpcEnable: true, GrpcStreamingEnabled: true, GrpcStreamingFlushIntervalMs: 100, - GrpcStreamingMaxBatchSize: 2000, - GrpcStreamingMaxChannelBufferSize: 2000, + GrpcStreamingMaxBatchSize: 10000, + GrpcStreamingMaxChannelBufferSize: 10000, WebsocketStreamingEnabled: true, WebsocketStreamingPort: 8989, }, @@ -119,9 +119,9 @@ func TestValidate(t *testing.T) { GrpcEnable: true, GrpcStreamingEnabled: true, OptimisticExecutionEnabled: true, - GrpcStreamingMaxBatchSize: 2000, + GrpcStreamingMaxBatchSize: 10000, GrpcStreamingFlushIntervalMs: 100, - GrpcStreamingMaxChannelBufferSize: 2000, + GrpcStreamingMaxChannelBufferSize: 10000, WebsocketStreamingPort: 8989, }, }, @@ -257,8 +257,8 @@ func TestGetFlagValuesFromOptions(t *testing.T) { expectedGrpcEnable: true, expectedGrpcStreamingEnable: false, expectedGrpcStreamingFlushMs: 50, - expectedGrpcStreamingBatchSize: 2000, - expectedGrpcStreamingMaxChannelBufferSize: 2000, + expectedGrpcStreamingBatchSize: 10000, + expectedGrpcStreamingMaxChannelBufferSize: 10000, expectedWebsocketEnabled: false, expectedWebsocketPort: 9092, expectedFullNodeStreamingSnapshotInterval: 0, diff --git a/protocol/lib/metrics/metric_keys.go b/protocol/lib/metrics/metric_keys.go index c84abc2fb1..18ef5fab1b 100644 --- a/protocol/lib/metrics/metric_keys.go +++ b/protocol/lib/metrics/metric_keys.go @@ -73,9 +73,8 @@ const ( FullNodeGrpc = "full_node_grpc" GrpcSendOrderbookUpdatesLatency = "grpc_send_orderbook_updates_latency" GrpcSendOrderbookSnapshotLatency = "grpc_send_orderbook_snapshot_latency" - GrpcSendSubaccountSnapshotLatency = "grpc_send_subaccount_snapshot_latency" + GrpcSendSubaccountUpdateCount = "grpc_send_subaccount_update_count" GrpcSendOrderbookFillsLatency = "grpc_send_orderbook_fills_latency" - GrpcSendFinalizedSubaccountUpdatesLatency = "grpc_send_finalized_subaccount_updates_latency" GrpcAddUpdateToBufferCount = "grpc_add_update_to_buffer_count" GrpcAddToSubscriptionChannelCount = "grpc_add_to_subscription_channel_count" GrpcSendResponseToSubscriberCount = "grpc_send_response_to_subscriber_count" @@ -86,6 +85,7 @@ const ( GrpcStagedAllFinalizeBlockUpdatesCount = "grpc_staged_all_finalize_block_updates_count" GrpcStagedFillFinalizeBlockUpdatesCount = "grpc_staged_finalize_block_fill_updates_count" GrpcStagedSubaccountFinalizeBlockUpdatesCount = "grpc_staged_finalize_block_subaccount_updates_count" + SubscriptionId = "subscription_id" EndBlocker = "end_blocker" EndBlockerLag = "end_blocker_lag" diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index f63beac347..6cf24bd0b5 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -153,7 +153,7 @@ func (sm *FullNodeStreamingManagerImpl) Enabled() bool { } func (sm *FullNodeStreamingManagerImpl) EmitMetrics() { - metrics.SetGauge( + metrics.AddSample( metrics.GrpcStreamNumUpdatesBuffered, float32(len(sm.streamUpdateCache)), ) @@ -162,9 +162,10 @@ func (sm *FullNodeStreamingManagerImpl) EmitMetrics() { float32(len(sm.orderbookSubscriptions)), ) for _, subscription := range sm.orderbookSubscriptions { - metrics.AddSample( + metrics.AddSampleWithLabels( metrics.GrpcSubscriptionChannelLength, float32(len(subscription.updatesChannel)), + metrics.GetLabelForIntValue(metrics.SubscriptionId, int(subscription.subscriptionId)), ) } } @@ -234,9 +235,10 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( // Use current goroutine to consistently poll subscription channel for updates // to send through stream. for updates := range subscription.updatesChannel { - metrics.IncrCounter( + metrics.IncrCounterWithLabels( metrics.GrpcSendResponseToSubscriberCount, 1, + metrics.GetLabelForIntValue(metrics.SubscriptionId, int(subscription.subscriptionId)), ) err = subscription.messageSender.Send( &clobtypes.StreamOrderbookUpdatesResponse{ @@ -372,9 +374,17 @@ func (sm *FullNodeStreamingManagerImpl) sendStreamUpdates( return } + metrics.IncrCounterWithLabels( + metrics.GrpcAddToSubscriptionChannelCount, + 1, + metrics.GetLabelForIntValue(metrics.SubscriptionId, int(subscriptionId)), + ) + select { case subscription.updatesChannel <- streamUpdates: default: + // Buffer is full. Emit metric and drop subscription. + sm.EmitMetrics() sm.logger.Error( fmt.Sprintf( "Streaming subscription id %+v channel full capacity. Dropping subscription connection.", @@ -399,6 +409,11 @@ func (sm *FullNodeStreamingManagerImpl) SendSubaccountUpdate( return } + metrics.IncrCounter( + metrics.GrpcSendSubaccountUpdateCount, + 1, + ) + // If `DeliverTx`, updates should be staged to be streamed after consensus finalizes on a block. stagedEvent := clobtypes.StagedFinalizeBlockEvent{ Event: &clobtypes.StagedFinalizeBlockEvent_SubaccountUpdate{ @@ -705,9 +720,9 @@ func (sm *FullNodeStreamingManagerImpl) AddOrderUpdatesToCache( sm.cacheStreamUpdatesByClobPairWithLock(updates, clobPairIds) + sm.EmitMetrics() // Remove all subscriptions and wipe the buffer if buffer overflows. sm.RemoveSubscriptionsAndClearBufferIfFull() - sm.EmitMetrics() } // AddSubaccountUpdatesToCache adds a series of updates to the full node streaming cache. @@ -726,8 +741,8 @@ func (sm *FullNodeStreamingManagerImpl) AddSubaccountUpdatesToCache( sm.cacheStreamUpdatesBySubaccountWithLock(updates, subaccountIds) - sm.RemoveSubscriptionsAndClearBufferIfFull() sm.EmitMetrics() + sm.RemoveSubscriptionsAndClearBufferIfFull() } // RemoveSubscriptionsAndClearBufferIfFull removes all subscriptions and wipes the buffer if buffer overflows. @@ -743,6 +758,7 @@ func (sm *FullNodeStreamingManagerImpl) RemoveSubscriptionsAndClearBufferIfFull( } sm.streamUpdateCache = nil sm.streamUpdateSubscriptionCache = nil + sm.EmitMetrics() } } @@ -778,13 +794,16 @@ func (sm *FullNodeStreamingManagerImpl) FlushStreamUpdatesWithLock() { // If the buffer is full, drop the subscription. for id, updates := range subscriptionUpdates { if subscription, ok := sm.orderbookSubscriptions[id]; ok { - metrics.IncrCounter( + metrics.IncrCounterWithLabels( metrics.GrpcAddToSubscriptionChannelCount, 1, + metrics.GetLabelForIntValue(metrics.SubscriptionId, int(id)), ) select { case subscription.updatesChannel <- updates: default: + // Buffer is full. Emit metric and drop subscription. + sm.EmitMetrics() idsToRemove = append(idsToRemove, id) } } diff --git a/protocol/streaming/ws/websocket_server.go b/protocol/streaming/ws/websocket_server.go index 0b66804595..c94e84208e 100644 --- a/protocol/streaming/ws/websocket_server.go +++ b/protocol/streaming/ws/websocket_server.go @@ -56,6 +56,9 @@ func (ws *WebsocketServer) Handler(w http.ResponseWriter, r *http.Request) { } defer conn.Close() + // Set ws max message size to 10 mb. + conn.SetReadLimit(10 * 1024 * 1024) + // Parse clobPairIds from query parameters clobPairIds, err := parseClobPairIds(r) if err != nil { From 4e1779ca697c56af8cbed8c624151c6b90706fdf Mon Sep 17 00:00:00 2001 From: ttl33 <19664986+ttl33@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:49:43 -0400 Subject: [PATCH 093/120] Add script to get insurance fund balances (#2516) --- .../get_isolated_market_insurance_fund.py | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 protocol/scripts/markets/get_isolated_market_insurance_fund.py diff --git a/protocol/scripts/markets/get_isolated_market_insurance_fund.py b/protocol/scripts/markets/get_isolated_market_insurance_fund.py new file mode 100644 index 0000000000..ee68b536af --- /dev/null +++ b/protocol/scripts/markets/get_isolated_market_insurance_fund.py @@ -0,0 +1,201 @@ +import argparse +import requests +import subprocess + +""" +Instructions: + +1. Install `requests` library + + `pip3 install requests` + +2. Build `dydxprotocold` by running `make build` in the root directory of the protocol repository + + `cd v4-chain/protocol && make clean && make build` + +3. Run the script using the correct endpoint and binary path. Example: + + `python3 scripts/markets/get_isolated_market_insurance_fund.py \ + --endpoint=https://dydx-ops-rest.kingnodes.com \ + --binary_path=/Users/taehoonlee/v4-chain/protocol/build/dydxprotocold` +""" + +def get_id_to_pair(base_endpoint_url): + endpoint_url = base_endpoint_url + "/dydxprotocol/prices/params/market" + + id_to_pair = {} + + # Pagination key + pagination_key = None + + while True: + # Build the URL with pagination key if it exists + url = f"{endpoint_url}" + if pagination_key: + url += f"?pagination.key={pagination_key}" + + try: + # Make the GET request + response = requests.get(url) + response.raise_for_status() # Raise an exception for HTTP errors + + # Parse the JSON response + data = response.json() + + # Extract + for market in data.get('market_params', []): + id_to_pair[market.get('id')] = market.get('pair') + + # Check if there is a next pagination key + pagination_key = data.get('pagination', {}).get('next_key') + + # If no more pages, break the loop + if not pagination_key: + break + + except requests.RequestException as e: + print(f"Request failed: {e}") + break + + return id_to_pair + + +def get_isolated_market_ids(base_endpoint_url): + endpoint_url = base_endpoint_url + "/dydxprotocol/perpetuals/perpetual" + + # Initialize the result list for matching market_ids + matching_market_ids = [] + + # Pagination key + pagination_key = None + + while True: + # Build the URL with pagination key if it exists + url = f"{endpoint_url}" + if pagination_key: + url += f"?pagination.key={pagination_key}" + + try: + # Make the GET request + response = requests.get(url) + response.raise_for_status() # Raise an exception for HTTP errors + + # Parse the JSON response + data = response.json() + + # Extract and filter market_ids where market_type matches the criteria + for market in data.get('perpetual', []): + market_params = market.get('params') + if market_params.get('market_type') == 'PERPETUAL_MARKET_TYPE_ISOLATED': + matching_market_ids.append(market_params.get('market_id')) + + # Check if there is a next pagination key + pagination_key = data.get('pagination', {}).get('next_key') + + # If no more pages, break the loop + if not pagination_key: + break + + except requests.RequestException as e: + print(f"Request failed: {e}") + break + + return matching_market_ids + +def run_dydxprotocold(command): + try: + # Run the command and capture the output + result = subprocess.run(command, capture_output=True, text=True, check=True) + return result.stdout + + except subprocess.CalledProcessError as e: + # Handle errors during command execution + print(f"Error running dydxprotocold \n{e.stderr}") + + except FileNotFoundError: + # Handle the case where the binary is not found + print("Error: dydxprotocold binary not found. Ensure you ran `make build`.") + +def get_insurance_fund_address_for_markets(binary_path, market_ids): + """ + This function takes a list of market_ids and runs the `dydxprotocold` binary for each. + It prints the output and errors, if any. + """ + + market_id_to_address = [] + + for market_id in market_ids: + # Construct the command + command = [binary_path, "q", "module-name-to-address", "insurance_fund:" + str(market_id)] + address = run_dydxprotocold(command) + if not address: + raise Exception(f"Failed to get insurance fund address for market_id: {market_id}") + market_id_to_address.append((market_id, address)) + + return market_id_to_address + +def get_bank_balance(market_id_to_address, base_endpoint_url): + url = base_endpoint_url + "/cosmos/bank/v1beta1/balances/" + + address_to_balance = {} + + for _, address in market_id_to_address: + try: + # Make the GET request + response = requests.get(url + address) + response.raise_for_status() # Raise an exception for HTTP errors + + # Parse the JSON response + data = response.json() + balances = data.get('balances', []) + bank_balance = 0 + + if len(balances) > 1: + raise ValueError("Expected at most one balance entry.") + if len(balances) == 1: + if balances[0].get('denom') != 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5': + raise ValueError("Unexpected 'denom' value in balances.") + bank_balance = int(balances[0].get('amount')) + bank_balance = bank_balance / (10 ** 6) + address_to_balance[address] = bank_balance + + except requests.RequestException as e: + print(f"Request failed: {e}") + break + + return address_to_balance + + +def print_market_info(market_id_to_address, address_to_balance, id_to_pair): + """ + Prints market information with aligned columns for better readability. + """ + header = f"{'Market':<15} {'ID':<5} {'Insurance Addr':<58} {'Bank Balance':>15}" + print(header) + print("-" * len(header)) # Separator line + + for market_id, address in market_id_to_address: + pair = id_to_pair.get(market_id) + balance = address_to_balance.get(address) + + print( + f"{pair:<15} " + f"{market_id:<5} " + f"{address:<58} " + f"{balance:>15.6f}" + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Get insurance fund balances for all isolated markets.') + parser.add_argument('--endpoint', required=True, help='The endpoint URL to fetch the markets.') + parser.add_argument('--binary_path', required=True, help='The local path to the `dydxprotocold` binary.') + args = parser.parse_args() + endpoint = args.endpoint + binary_path = args.binary_path + + id_to_pair = get_id_to_pair(endpoint) + market_ids = get_isolated_market_ids(endpoint) + market_id_to_address = get_insurance_fund_address_for_markets(binary_path, market_ids) + address_to_balance = get_bank_balance(market_id_to_address, endpoint) + print_market_info(market_id_to_address, address_to_balance, id_to_pair) From 2c7241341f9b12bc25e7b672907ed430a8401569 Mon Sep 17 00:00:00 2001 From: Jonathan Fung <121899091+jonfung-dydx@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:49:41 -0400 Subject: [PATCH 094/120] reusing subscription ids (#2518) --- .../streaming/full_node_streaming_manager.go | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index 6cf24bd0b5..af0d5671cd 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -35,7 +35,7 @@ type FullNodeStreamingManagerImpl struct { // orderbookSubscriptions maps subscription IDs to their respective orderbook subscriptions. orderbookSubscriptions map[uint32]*OrderbookSubscription - nextSubscriptionId uint32 + activeSubscriptionIds map[uint32]bool // stream will batch and flush out messages every 10 ms. ticker *time.Ticker @@ -106,7 +106,7 @@ func NewFullNodeStreamingManager( fullNodeStreamingManager := &FullNodeStreamingManagerImpl{ logger: logger, orderbookSubscriptions: make(map[uint32]*OrderbookSubscription), - nextSubscriptionId: 0, + activeSubscriptionIds: make(map[uint32]bool), ticker: time.NewTicker(time.Duration(flushIntervalMs) * time.Millisecond), done: make(chan bool), @@ -170,6 +170,16 @@ func (sm *FullNodeStreamingManagerImpl) EmitMetrics() { } } +// getNextAvailableSubscriptionId returns next available subscription id. Assumes the +// lock has been acquired. +func (sm *FullNodeStreamingManagerImpl) getNextAvailableSubscriptionId() uint32 { + id := uint32(0) + for _, inUse := sm.activeSubscriptionIds[id]; inUse; _, inUse = sm.activeSubscriptionIds[id] { + id = id + uint32(1) + } + return id +} + // Subscribe subscribes to the orderbook updates stream. func (sm *FullNodeStreamingManagerImpl) Subscribe( clobPairIds []uint32, @@ -188,8 +198,11 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( for i, subaccountId := range subaccountIds { sIds[i] = *subaccountId } + + subscriptionId := sm.getNextAvailableSubscriptionId() + subscription := &OrderbookSubscription{ - subscriptionId: sm.nextSubscriptionId, + subscriptionId: subscriptionId, initialized: &atomic.Bool{}, // False by default. clobPairIds: clobPairIds, subaccountIds: sIds, @@ -204,7 +217,7 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( } sm.clobPairIdToSubscriptionIdMapping[clobPairId] = append( sm.clobPairIdToSubscriptionIdMapping[clobPairId], - sm.nextSubscriptionId, + subscription.subscriptionId, ) } for _, subaccountId := range sIds { @@ -215,7 +228,7 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( } sm.subaccountIdToSubscriptionIdMapping[subaccountId] = append( sm.subaccountIdToSubscriptionIdMapping[subaccountId], - sm.nextSubscriptionId, + subscription.subscriptionId, ) } @@ -228,7 +241,7 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( ), ) sm.orderbookSubscriptions[subscription.subscriptionId] = subscription - sm.nextSubscriptionId++ + sm.activeSubscriptionIds[subscription.subscriptionId] = true sm.EmitMetrics() sm.Unlock() @@ -280,6 +293,7 @@ func (sm *FullNodeStreamingManagerImpl) removeSubscription( } close(subscription.updatesChannel) delete(sm.orderbookSubscriptions, subscriptionIdToRemove) + delete(sm.activeSubscriptionIds, subscriptionIdToRemove) // Iterate over the clobPairIdToSubscriptionIdMapping to remove the subscriptionIdToRemove for pairId, subscriptionIds := range sm.clobPairIdToSubscriptionIdMapping { From fbd671af3de34697752b1918e1dcdeece1f2e86f Mon Sep 17 00:00:00 2001 From: Jonathan Fung <121899091+jonfung-dydx@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:56:53 -0400 Subject: [PATCH 095/120] FNS - bounds check raw subscription payload int vals (#2523) --- protocol/streaming/ws/websocket_server.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocol/streaming/ws/websocket_server.go b/protocol/streaming/ws/websocket_server.go index c94e84208e..ba4477d03b 100644 --- a/protocol/streaming/ws/websocket_server.go +++ b/protocol/streaming/ws/websocket_server.go @@ -3,6 +3,7 @@ package ws import ( "context" "fmt" + "math" "net/http" "strconv" "strings" @@ -122,6 +123,10 @@ func parseSubaccountIds(r *http.Request) ([]*satypes.SubaccountId, error) { return nil, fmt.Errorf("invalid subaccount number: %s, expected subaccount_id format: owner/number", parts[1]) } + if number < 0 || number > math.MaxInt32 { + return nil, fmt.Errorf("invalid subaccount number: %s", parts[1]) + } + subaccountIds = append(subaccountIds, &satypes.SubaccountId{ Owner: parts[0], Number: uint32(number), @@ -144,6 +149,9 @@ func parseClobPairIds(r *http.Request) ([]uint32, error) { if err != nil { return nil, fmt.Errorf("invalid clobPairId: %s", idStr) } + if id < 0 || id > math.MaxInt32 { + return nil, fmt.Errorf("invalid clob pair id: %s", idStr) + } clobPairIds = append(clobPairIds, uint32(id)) } From 6fb5a95f240b6fe6980397d5cbe7a4f8ebe8c8e5 Mon Sep 17 00:00:00 2001 From: Denis Kolodin Date: Tue, 22 Oct 2024 18:19:12 +0200 Subject: [PATCH 096/120] Protocol support for Rust (#2172) Co-authored-by: Maksim Ryndin Co-authored-by: v0-e --- .gitignore | 2 + v4-proto-rs/Cargo.toml | 19 + v4-proto-rs/README.md | 62 + v4-proto-rs/build.rs | 28 + v4-proto-rs/deny.toml | 56 + v4-proto-rs/src/_includes.rs | 110 + v4-proto-rs/src/cosmos.base.query.v1beta1.rs | 77 + v4-proto-rs/src/cosmos.base.v1beta1.rs | 81 + v4-proto-rs/src/cosmos_proto.rs | 94 + v4-proto-rs/src/dydxprotocol.assets.rs | 371 ++ v4-proto-rs/src/dydxprotocol.blocktime.rs | 520 +++ v4-proto-rs/src/dydxprotocol.bridge.rs | 1033 ++++++ v4-proto-rs/src/dydxprotocol.clob.rs | 2984 +++++++++++++++++ .../src/dydxprotocol.daemons.bridge.rs | 152 + .../src/dydxprotocol.daemons.liquidation.rs | 171 + .../src/dydxprotocol.daemons.pricefeed.rs | 191 ++ v4-proto-rs/src/dydxprotocol.delaymsg.rs | 498 +++ v4-proto-rs/src/dydxprotocol.epochs.rs | 284 ++ v4-proto-rs/src/dydxprotocol.feetiers.rs | 436 +++ v4-proto-rs/src/dydxprotocol.govplus.rs | 275 ++ .../src/dydxprotocol.indexer.events.rs | 1046 ++++++ .../dydxprotocol.indexer.indexer_manager.rs | 162 + .../dydxprotocol.indexer.off_chain_updates.rs | 256 ++ .../src/dydxprotocol.indexer.protocol.v1.rs | 450 +++ v4-proto-rs/src/dydxprotocol.indexer.redis.rs | 83 + .../src/dydxprotocol.indexer.shared.rs | 125 + v4-proto-rs/src/dydxprotocol.indexer.socks.rs | 196 ++ v4-proto-rs/src/dydxprotocol.perpetuals.rs | 1152 +++++++ v4-proto-rs/src/dydxprotocol.prices.rs | 737 ++++ v4-proto-rs/src/dydxprotocol.ratelimit.rs | 557 +++ v4-proto-rs/src/dydxprotocol.rewards.rs | 366 ++ v4-proto-rs/src/dydxprotocol.sending.rs | 498 +++ v4-proto-rs/src/dydxprotocol.stats.rs | 651 ++++ v4-proto-rs/src/dydxprotocol.subaccounts.rs | 490 +++ v4-proto-rs/src/dydxprotocol.vault.rs | 711 ++++ v4-proto-rs/src/dydxprotocol.vest.rs | 410 +++ v4-proto-rs/src/google.api.rs | 402 +++ v4-proto-rs/src/lib.rs | 45 + 38 files changed, 15781 insertions(+) create mode 100644 v4-proto-rs/Cargo.toml create mode 100644 v4-proto-rs/README.md create mode 100644 v4-proto-rs/build.rs create mode 100644 v4-proto-rs/deny.toml create mode 100644 v4-proto-rs/src/_includes.rs create mode 100644 v4-proto-rs/src/cosmos.base.query.v1beta1.rs create mode 100644 v4-proto-rs/src/cosmos.base.v1beta1.rs create mode 100644 v4-proto-rs/src/cosmos_proto.rs create mode 100644 v4-proto-rs/src/dydxprotocol.assets.rs create mode 100644 v4-proto-rs/src/dydxprotocol.blocktime.rs create mode 100644 v4-proto-rs/src/dydxprotocol.bridge.rs create mode 100644 v4-proto-rs/src/dydxprotocol.clob.rs create mode 100644 v4-proto-rs/src/dydxprotocol.daemons.bridge.rs create mode 100644 v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs create mode 100644 v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs create mode 100644 v4-proto-rs/src/dydxprotocol.delaymsg.rs create mode 100644 v4-proto-rs/src/dydxprotocol.epochs.rs create mode 100644 v4-proto-rs/src/dydxprotocol.feetiers.rs create mode 100644 v4-proto-rs/src/dydxprotocol.govplus.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.events.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.redis.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.shared.rs create mode 100644 v4-proto-rs/src/dydxprotocol.indexer.socks.rs create mode 100644 v4-proto-rs/src/dydxprotocol.perpetuals.rs create mode 100644 v4-proto-rs/src/dydxprotocol.prices.rs create mode 100644 v4-proto-rs/src/dydxprotocol.ratelimit.rs create mode 100644 v4-proto-rs/src/dydxprotocol.rewards.rs create mode 100644 v4-proto-rs/src/dydxprotocol.sending.rs create mode 100644 v4-proto-rs/src/dydxprotocol.stats.rs create mode 100644 v4-proto-rs/src/dydxprotocol.subaccounts.rs create mode 100644 v4-proto-rs/src/dydxprotocol.vault.rs create mode 100644 v4-proto-rs/src/dydxprotocol.vest.rs create mode 100644 v4-proto-rs/src/google.api.rs create mode 100644 v4-proto-rs/src/lib.rs diff --git a/.gitignore b/.gitignore index bbbe817346..05ae345c17 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ v4-proto-py/v4_proto v4-proto-js/build v4-proto-js/node_modules v4-proto-js/src +v4-proto-rs/target +v4-proto-rs/Cargo.lock .idea .vscode diff --git a/v4-proto-rs/Cargo.toml b/v4-proto-rs/Cargo.toml new file mode 100644 index 0000000000..a76ce4d45c --- /dev/null +++ b/v4-proto-rs/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "v4-proto-rs" +version = "0.1.0" +edition = "2021" +license = "AGPL-3.0" + +[lib] +doctest = false + +[dependencies] +cosmos-sdk-proto = "0.21.1" +tonic = { version = "0.11", features = ["tls", "tls-roots", "transport", "channel"] } +prost = "0.12" +prost-types = "0.12" + +[build-dependencies] +tonic-buf-build = "0.2.1" +prost-build = "0.12" # keep the version the same as in tonic-buf-build +tonic-build = "0.11" # keep the version the same as in tonic-buf-build diff --git a/v4-proto-rs/README.md b/v4-proto-rs/README.md new file mode 100644 index 0000000000..551c7d6ce0 --- /dev/null +++ b/v4-proto-rs/README.md @@ -0,0 +1,62 @@ +# Rust crate for dYdX Chain protobufs + +## Usage as a dependency + +Cargo.toml + +```toml +[dependencies] +v4-proto-rs = "0.1" +``` + +*Note:* by default, rust stub files are not rebuilt (see Q&A below) + +For more idiomatic Rust you can use conversions (`try_into` and `into`) for the following types: +* `prost_types::Timestamp` -> `std::time::SystemTime` +* `prost_types::Duration`-> `std::time::Duration` + +## Local development + +### Prerequisites +1) [Rust](https://www.rust-lang.org/tools/install) +2) [Buf](https://github.com/bufbuild/buf?tab=readme-ov-file#installation) - to resolve 3rd-party dependencies for protobuf files +3) [protoc](https://github.com/protocolbuffers/protobuf#protobuf-compiler-installation) - to compile protobuf files with their 3rd-party dependencies +4) [cargo deny](https://github.com/EmbarkStudios/cargo-deny) - to check for security/license/sources issues + +Then for a code (re-)generation run + +```sh +V4_PROTO_REBUILD=1 cargo build -vv +``` + +Before publishing make sure to run (and fix all warnings and errors) + +```sh +cargo fmt +cargo clippy +cargo deny check licenses advisories sources +``` + +## Q&A + +1) Why do we put autogenerated files to the crate (and git) and do not (re-)generate them at compilation? + + For several reasons: + * reproducibility of the dependency + * to avoid external dependencies for the lib users (`protoc` and `buf` are only needed for code generation) + + But if a user wants to (re-)generate at compilation time, he/she can set an environment variable `V4_PROTO_REBUILD` (to any value). + +2) Why do I need a `protoc` for this crate development? I thought `prost-build` crate generates everything natively with Rust? + + The main work (parsing, linking, etc. - have a look https://protobuf.com/docs/descriptors) is done by `protoc`. + The result of the `protoc` work is a "file descriptor" (think of it as IR assembly language like LLVM IR) - a binary file. This file descriptor is an input for a language-specific code generator like `prost`. Think of `prost` crate as a compiler target which generates a ISA-specific "assembly" (in our case, Rust) as an output. + `prost-build` always used the `protoc` but since version 0.11 of [prost-build](https://github.com/tokio-rs/prost?tab=readme-ov-file#protoc) it requires `protoc` (the protobuf compiler) to be already installed on the system - before the `protoc` could be compiled during the `prost-build` build (https://github.com/tokio-rs/prost/blob/v0.10.4/prost-build/build.rs#L77). + +3) Why do we use `tonic-build` crate and not just `prost-build`? + + `prost-build` generates only serialization-deserialization stubs for messages, but we also need a client implementation (generated by `tonic-build`) because packages in other language implementations of `v4-chain` have ones. + +4) Why do we need `buf`? + + [Buf](https://buf.build/) is a tool whose primary function is to resolve dependencies in protobuf files. Protobuf specifications can refer to 3rd-party protobuf specifications and use types declared there. Basically, `buf` builds a list of all used protobuf files, downloads them, and allows exporting (=copying) them to a specified directory. The proto files in this repository and downloaded 3rd-party proto files (aka "includes") are an input for the `protoc`. diff --git a/v4-proto-rs/build.rs b/v4-proto-rs/build.rs new file mode 100644 index 0000000000..dfad90ed8c --- /dev/null +++ b/v4-proto-rs/build.rs @@ -0,0 +1,28 @@ +use prost_build::Config; +use std::env; +use std::path::PathBuf; + +fn main() -> Result<(), tonic_buf_build::error::TonicBufBuildError> { + if std::env::var("V4_PROTO_REBUILD").is_ok() { + let mut config = Config::new(); + config.out_dir("src"); + config.include_file("_includes.rs"); + config.enable_type_names(); + let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|e| { + tonic_buf_build::error::TonicBufBuildError { + message: format!("Failed to get CARGO_MANIFEST_DIR: {}", e), + cause: None, + } + })?); + path.pop(); + tonic_buf_build::compile_from_buf_workspace_with_config( + tonic_build::configure().build_server(false), + Some(config), + tonic_buf_build::TonicBufConfig { + buf_dir: Some(path), + }, + )?; + } + + Ok(()) +} diff --git a/v4-proto-rs/deny.toml b/v4-proto-rs/deny.toml new file mode 100644 index 0000000000..198bd0af13 --- /dev/null +++ b/v4-proto-rs/deny.toml @@ -0,0 +1,56 @@ +[graph] +targets = [ + { triple = "x86_64-unknown-linux-gnu" }, + { triple = "aarch64-unknown-linux-gnu" }, + { triple = "x86_64-unknown-linux-musl" }, + { triple = "aarch64-apple-darwin" }, + { triple = "x86_64-apple-darwin" }, + { triple = "x86_64-pc-windows-msvc" }, +] +all-features = false +no-default-features = false + +[output] +feature-depth = 1 + +[advisories] +db-path = "~/.cargo/advisory-db" +db-urls = ["https://github.com/rustsec/advisory-db"] + +[licenses] +allow = [ + "MIT", + "Apache-2.0", + "BSD-3-Clause", + "ISC", + "Unicode-DFS-2016", + "OpenSSL", +] +confidence-threshold = 0.8 +exceptions = [] + +[[licenses.clarify]] +name = "ring" +expression = "MIT AND ISC AND OpenSSL" +license-files = [ + { path = "LICENSE", hash = 0xbd0eed23 } +] + +[licenses.private] +ignore = false +registries = [] + +[bans] +multiple-versions = "warn" +wildcards = "allow" +highlight = "all" + +[sources] +unknown-registry = "warn" +unknown-git = "warn" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] + +[sources.allow-org] +github = [] +gitlab = [] +bitbucket = [] \ No newline at end of file diff --git a/v4-proto-rs/src/_includes.rs b/v4-proto-rs/src/_includes.rs new file mode 100644 index 0000000000..edcb46e6a8 --- /dev/null +++ b/v4-proto-rs/src/_includes.rs @@ -0,0 +1,110 @@ +// This file is @generated by prost-build. +pub mod cosmos { + pub mod base { + pub mod query { + pub mod v1beta1 { + include!("cosmos.base.query.v1beta1.rs"); + } + } + pub mod v1beta1 { + include!("cosmos.base.v1beta1.rs"); + } + } +} +pub mod cosmos_proto { + include!("cosmos_proto.rs"); +} +pub mod dydxprotocol { + pub mod assets { + include!("dydxprotocol.assets.rs"); + } + pub mod blocktime { + include!("dydxprotocol.blocktime.rs"); + } + pub mod bridge { + include!("dydxprotocol.bridge.rs"); + } + pub mod clob { + include!("dydxprotocol.clob.rs"); + } + pub mod daemons { + pub mod bridge { + include!("dydxprotocol.daemons.bridge.rs"); + } + pub mod liquidation { + include!("dydxprotocol.daemons.liquidation.rs"); + } + pub mod pricefeed { + include!("dydxprotocol.daemons.pricefeed.rs"); + } + } + pub mod delaymsg { + include!("dydxprotocol.delaymsg.rs"); + } + pub mod epochs { + include!("dydxprotocol.epochs.rs"); + } + pub mod feetiers { + include!("dydxprotocol.feetiers.rs"); + } + pub mod govplus { + include!("dydxprotocol.govplus.rs"); + } + pub mod indexer { + pub mod events { + include!("dydxprotocol.indexer.events.rs"); + } + pub mod indexer_manager { + include!("dydxprotocol.indexer.indexer_manager.rs"); + } + pub mod off_chain_updates { + include!("dydxprotocol.indexer.off_chain_updates.rs"); + } + pub mod protocol { + pub mod v1 { + include!("dydxprotocol.indexer.protocol.v1.rs"); + } + } + pub mod redis { + include!("dydxprotocol.indexer.redis.rs"); + } + pub mod shared { + include!("dydxprotocol.indexer.shared.rs"); + } + pub mod socks { + include!("dydxprotocol.indexer.socks.rs"); + } + } + pub mod perpetuals { + include!("dydxprotocol.perpetuals.rs"); + } + pub mod prices { + include!("dydxprotocol.prices.rs"); + } + pub mod ratelimit { + include!("dydxprotocol.ratelimit.rs"); + } + pub mod rewards { + include!("dydxprotocol.rewards.rs"); + } + pub mod sending { + include!("dydxprotocol.sending.rs"); + } + pub mod stats { + include!("dydxprotocol.stats.rs"); + } + pub mod subaccounts { + include!("dydxprotocol.subaccounts.rs"); + } + pub mod vault { + include!("dydxprotocol.vault.rs"); + } + pub mod vest { + include!("dydxprotocol.vest.rs"); + } +} +pub mod google { + pub mod api { + include!("google.api.rs"); + } +} diff --git a/v4-proto-rs/src/cosmos.base.query.v1beta1.rs b/v4-proto-rs/src/cosmos.base.query.v1beta1.rs new file mode 100644 index 0000000000..dc11f529f4 --- /dev/null +++ b/v4-proto-rs/src/cosmos.base.query.v1beta1.rs @@ -0,0 +1,77 @@ +// This file is @generated by prost-build. +/// PageRequest is to be embedded in gRPC request messages for efficient +/// pagination. Ex: +/// +/// message SomeRequest { +/// Foo some_parameter = 1; +/// PageRequest pagination = 2; +/// } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PageRequest { + /// key is a value returned in PageResponse.next_key to begin + /// querying the next page most efficiently. Only one of offset or key + /// should be set. + #[prost(bytes = "vec", tag = "1")] + pub key: ::prost::alloc::vec::Vec, + /// offset is a numeric offset that can be used when key is unavailable. + /// It is less efficient than using key. Only one of offset or key should + /// be set. + #[prost(uint64, tag = "2")] + pub offset: u64, + /// limit is the total number of results to be returned in the result page. + /// If left empty it will default to a value to be set by each app. + #[prost(uint64, tag = "3")] + pub limit: u64, + /// count_total is set to true to indicate that the result set should include + /// a count of the total number of items available for pagination in UIs. + /// count_total is only respected when offset is used. It is ignored when key + /// is set. + #[prost(bool, tag = "4")] + pub count_total: bool, + /// reverse is set to true if results are to be returned in the descending order. + /// + /// Since: cosmos-sdk 0.43 + #[prost(bool, tag = "5")] + pub reverse: bool, +} +impl ::prost::Name for PageRequest { + const NAME: &'static str = "PageRequest"; + const PACKAGE: &'static str = "cosmos.base.query.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.query.v1beta1.PageRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.query.v1beta1.PageRequest".into() + } +} +/// PageResponse is to be embedded in gRPC response messages where the +/// corresponding request message has used PageRequest. +/// +/// message SomeResponse { +/// repeated Bar results = 1; +/// PageResponse page = 2; +/// } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PageResponse { + /// next_key is the key to be passed to PageRequest.key to + /// query the next page most efficiently. It will be empty if + /// there are no more results. + #[prost(bytes = "vec", tag = "1")] + pub next_key: ::prost::alloc::vec::Vec, + /// total is total number of results available if PageRequest.count_total + /// was set, its value is undefined otherwise + #[prost(uint64, tag = "2")] + pub total: u64, +} +impl ::prost::Name for PageResponse { + const NAME: &'static str = "PageResponse"; + const PACKAGE: &'static str = "cosmos.base.query.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.query.v1beta1.PageResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.query.v1beta1.PageResponse".into() + } +} diff --git a/v4-proto-rs/src/cosmos.base.v1beta1.rs b/v4-proto-rs/src/cosmos.base.v1beta1.rs new file mode 100644 index 0000000000..8a61cfab7a --- /dev/null +++ b/v4-proto-rs/src/cosmos.base.v1beta1.rs @@ -0,0 +1,81 @@ +// This file is @generated by prost-build. +/// Coin defines a token with a denomination and an amount. +/// +/// NOTE: The amount field is an Int which implements the custom method +/// signatures required by gogoproto. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Coin { + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub amount: ::prost::alloc::string::String, +} +impl ::prost::Name for Coin { + const NAME: &'static str = "Coin"; + const PACKAGE: &'static str = "cosmos.base.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.v1beta1.Coin".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.v1beta1.Coin".into() + } +} +/// DecCoin defines a token with a denomination and a decimal amount. +/// +/// NOTE: The amount field is an Dec which implements the custom method +/// signatures required by gogoproto. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DecCoin { + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub amount: ::prost::alloc::string::String, +} +impl ::prost::Name for DecCoin { + const NAME: &'static str = "DecCoin"; + const PACKAGE: &'static str = "cosmos.base.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.v1beta1.DecCoin".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.v1beta1.DecCoin".into() + } +} +/// IntProto defines a Protobuf wrapper around an Int object. +/// Deprecated: Prefer to use math.Int directly. It supports binary Marshal and Unmarshal. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IntProto { + #[prost(string, tag = "1")] + pub int: ::prost::alloc::string::String, +} +impl ::prost::Name for IntProto { + const NAME: &'static str = "IntProto"; + const PACKAGE: &'static str = "cosmos.base.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.v1beta1.IntProto".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.v1beta1.IntProto".into() + } +} +/// DecProto defines a Protobuf wrapper around a Dec object. +/// Deprecated: Prefer to use math.LegacyDec directly. It supports binary Marshal and Unmarshal. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DecProto { + #[prost(string, tag = "1")] + pub dec: ::prost::alloc::string::String, +} +impl ::prost::Name for DecProto { + const NAME: &'static str = "DecProto"; + const PACKAGE: &'static str = "cosmos.base.v1beta1"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos.base.v1beta1.DecProto".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos.base.v1beta1.DecProto".into() + } +} diff --git a/v4-proto-rs/src/cosmos_proto.rs b/v4-proto-rs/src/cosmos_proto.rs new file mode 100644 index 0000000000..e45172e7ee --- /dev/null +++ b/v4-proto-rs/src/cosmos_proto.rs @@ -0,0 +1,94 @@ +// This file is @generated by prost-build. +/// InterfaceDescriptor describes an interface type to be used with +/// accepts_interface and implements_interface and declared by declare_interface. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InterfaceDescriptor { + /// name is the name of the interface. It should be a short-name (without + /// a period) such that the fully qualified name of the interface will be + /// package.name, ex. for the package a.b and interface named C, the + /// fully-qualified name will be a.b.C. + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + /// description is a human-readable description of the interface and its + /// purpose. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, +} +impl ::prost::Name for InterfaceDescriptor { + const NAME: &'static str = "InterfaceDescriptor"; + const PACKAGE: &'static str = "cosmos_proto"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos_proto.InterfaceDescriptor".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos_proto.InterfaceDescriptor".into() + } +} +/// ScalarDescriptor describes an scalar type to be used with +/// the scalar field option and declared by declare_scalar. +/// Scalars extend simple protobuf built-in types with additional +/// syntax and semantics, for instance to represent big integers. +/// Scalars should ideally define an encoding such that there is only one +/// valid syntactical representation for a given semantic meaning, +/// i.e. the encoding should be deterministic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ScalarDescriptor { + /// name is the name of the scalar. It should be a short-name (without + /// a period) such that the fully qualified name of the scalar will be + /// package.name, ex. for the package a.b and scalar named C, the + /// fully-qualified name will be a.b.C. + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + /// description is a human-readable description of the scalar and its + /// encoding format. For instance a big integer or decimal scalar should + /// specify precisely the expected encoding format. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + /// field_type is the type of field with which this scalar can be used. + /// Scalars can be used with one and only one type of field so that + /// encoding standards and simple and clear. Currently only string and + /// bytes fields are supported for scalars. + #[prost(enumeration = "ScalarType", repeated, tag = "3")] + pub field_type: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for ScalarDescriptor { + const NAME: &'static str = "ScalarDescriptor"; + const PACKAGE: &'static str = "cosmos_proto"; + fn full_name() -> ::prost::alloc::string::String { + "cosmos_proto.ScalarDescriptor".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/cosmos_proto.ScalarDescriptor".into() + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ScalarType { + Unspecified = 0, + String = 1, + Bytes = 2, +} +impl ScalarType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ScalarType::Unspecified => "SCALAR_TYPE_UNSPECIFIED", + ScalarType::String => "SCALAR_TYPE_STRING", + ScalarType::Bytes => "SCALAR_TYPE_BYTES", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SCALAR_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "SCALAR_TYPE_STRING" => Some(Self::String), + "SCALAR_TYPE_BYTES" => Some(Self::Bytes), + _ => None, + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.assets.rs b/v4-proto-rs/src/dydxprotocol.assets.rs new file mode 100644 index 0000000000..04c175b7d0 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.assets.rs @@ -0,0 +1,371 @@ +// This file is @generated by prost-build. +/// Asset defines a single exchangable asset. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Asset { + /// Unique, sequentially-generated. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The human readable symbol of the `Asset` (e.g. `USDC`, `ATOM`). + /// Must be uppercase, unique and correspond to the canonical symbol of the + /// full coin. + #[prost(string, tag = "2")] + pub symbol: ::prost::alloc::string::String, + /// The name of base denomination unit of the `Asset` (e.g. `uatom`, + /// 'ibc/xxxxx'). Must be unique and match the `denom` used in the `sdk.Coin` + /// type in the `x/bank` module. + #[prost(string, tag = "3")] + pub denom: ::prost::alloc::string::String, + /// The exponent of converting one unit of `denom` to a full coin. + /// For example, `name=USDC, denom=uusdc, denom_exponent=-6` defines that + /// `1 uusdc = 10^(-6) USDC`. Note that `uusdc` refers to a `Coin` type in + /// `x/bank`, where the prefix `u` means `micro` by convetion. `uusdc` is + /// a different concept from a "quantum" defined by `atomic_resolution` below. + /// To convert from an amount of `denom` to quantums: + /// `quantums = denom_amount * 10^(denom_exponent - atomic_resolution)` + #[prost(sint32, tag = "4")] + pub denom_exponent: i32, + /// `true` if this `Asset` has a valid `MarketId` value. + #[prost(bool, tag = "5")] + pub has_market: bool, + /// The `Id` of the `Market` associated with this `Asset`. It acts as the + /// oracle price for the purposes of calculating collateral + /// and margin requirements. + #[prost(uint32, tag = "6")] + pub market_id: u32, + /// The exponent for converting an atomic amount (1 'quantum') + /// to a full coin. For example, if `atomic_resolution = -8` + /// then an `asset_position` with `base_quantums = 1e8` is equivalent to + /// a position size of one full coin. + #[prost(sint32, tag = "7")] + pub atomic_resolution: i32, +} +impl ::prost::Name for Asset { + const NAME: &'static str = "Asset"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.Asset".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.Asset".into() + } +} +/// GenesisState defines the assets module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub assets: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.GenesisState".into() + } +} +/// Queries an Asset by id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAssetRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryAssetRequest { + const NAME: &'static str = "QueryAssetRequest"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.QueryAssetRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.QueryAssetRequest".into() + } +} +/// QueryAssetResponse is response type for the Asset RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAssetResponse { + #[prost(message, optional, tag = "1")] + pub asset: ::core::option::Option, +} +impl ::prost::Name for QueryAssetResponse { + const NAME: &'static str = "QueryAssetResponse"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.QueryAssetResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.QueryAssetResponse".into() + } +} +/// Queries a list of Asset items. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllAssetsRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllAssetsRequest { + const NAME: &'static str = "QueryAllAssetsRequest"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.QueryAllAssetsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.QueryAllAssetsRequest".into() + } +} +/// QueryAllAssetsResponse is response type for the AllAssets RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllAssetsResponse { + #[prost(message, repeated, tag = "1")] + pub asset: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllAssetsResponse { + const NAME: &'static str = "QueryAllAssetsResponse"; + const PACKAGE: &'static str = "dydxprotocol.assets"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.assets.QueryAllAssetsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.assets.QueryAllAssetsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a Asset by id. + pub async fn asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.assets.Query/Asset", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.assets.Query", "Asset")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of Asset items. + pub async fn all_assets( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.assets.Query/AllAssets", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.assets.Query", "AllAssets")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.blocktime.rs b/v4-proto-rs/src/dydxprotocol.blocktime.rs new file mode 100644 index 0000000000..c92356fc7b --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.blocktime.rs @@ -0,0 +1,520 @@ +// This file is @generated by prost-build. +/// BlockInfo stores information about a block +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockInfo { + #[prost(uint32, tag = "1")] + pub height: u32, + #[prost(message, optional, tag = "2")] + pub timestamp: ::core::option::Option<::prost_types::Timestamp>, +} +impl ::prost::Name for BlockInfo { + const NAME: &'static str = "BlockInfo"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.BlockInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.BlockInfo".into() + } +} +/// AllDowntimeInfo stores information for all downtime durations. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AllDowntimeInfo { + /// The downtime information for each tracked duration. Sorted by duration, + /// ascending. (i.e. the same order as they appear in DowntimeParams). + #[prost(message, repeated, tag = "1")] + pub infos: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `AllDowntimeInfo`. +pub mod all_downtime_info { + /// Stores information about downtime. block_info corresponds to the most + /// recent block at which a downtime occurred. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DowntimeInfo { + #[prost(message, optional, tag = "1")] + pub duration: ::core::option::Option<::prost_types::Duration>, + #[prost(message, optional, tag = "2")] + pub block_info: ::core::option::Option, + } + impl ::prost::Name for DowntimeInfo { + const NAME: &'static str = "DowntimeInfo"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.AllDowntimeInfo.DowntimeInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.AllDowntimeInfo.DowntimeInfo".into() + } + } +} +impl ::prost::Name for AllDowntimeInfo { + const NAME: &'static str = "AllDowntimeInfo"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.AllDowntimeInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.AllDowntimeInfo".into() + } +} +/// DowntimeParams defines the parameters for downtime. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DowntimeParams { + /// Durations tracked for downtime. The durations must be sorted from + /// shortest to longest and must all be positive. + #[prost(message, repeated, tag = "1")] + pub durations: ::prost::alloc::vec::Vec<::prost_types::Duration>, +} +impl ::prost::Name for DowntimeParams { + const NAME: &'static str = "DowntimeParams"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.DowntimeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.DowntimeParams".into() + } +} +/// GenesisState defines the blocktime module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.GenesisState".into() + } +} +/// QueryDowntimeParamsRequest is a request type for the DowntimeParams +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryDowntimeParamsRequest {} +impl ::prost::Name for QueryDowntimeParamsRequest { + const NAME: &'static str = "QueryDowntimeParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryDowntimeParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryDowntimeParamsRequest".into() + } +} +/// QueryDowntimeParamsResponse is a response type for the DowntimeParams +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryDowntimeParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryDowntimeParamsResponse { + const NAME: &'static str = "QueryDowntimeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryDowntimeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryDowntimeParamsResponse".into() + } +} +/// QueryPreviousBlockInfoRequest is a request type for the PreviousBlockInfo +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPreviousBlockInfoRequest {} +impl ::prost::Name for QueryPreviousBlockInfoRequest { + const NAME: &'static str = "QueryPreviousBlockInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryPreviousBlockInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryPreviousBlockInfoRequest".into() + } +} +/// QueryPreviousBlockInfoResponse is a request type for the PreviousBlockInfo +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPreviousBlockInfoResponse { + #[prost(message, optional, tag = "1")] + pub info: ::core::option::Option, +} +impl ::prost::Name for QueryPreviousBlockInfoResponse { + const NAME: &'static str = "QueryPreviousBlockInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryPreviousBlockInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryPreviousBlockInfoResponse".into() + } +} +/// QueryAllDowntimeInfoRequest is a request type for the AllDowntimeInfo +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllDowntimeInfoRequest {} +impl ::prost::Name for QueryAllDowntimeInfoRequest { + const NAME: &'static str = "QueryAllDowntimeInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryAllDowntimeInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryAllDowntimeInfoRequest".into() + } +} +/// QueryAllDowntimeInfoResponse is a request type for the AllDowntimeInfo +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllDowntimeInfoResponse { + #[prost(message, optional, tag = "1")] + pub info: ::core::option::Option, +} +impl ::prost::Name for QueryAllDowntimeInfoResponse { + const NAME: &'static str = "QueryAllDowntimeInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.QueryAllDowntimeInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.QueryAllDowntimeInfoResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the DowntimeParams. + pub async fn downtime_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.blocktime.Query/DowntimeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.blocktime.Query", "DowntimeParams"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the information of the previous block + pub async fn previous_block_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.blocktime.Query/PreviousBlockInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.blocktime.Query", "PreviousBlockInfo"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries all recorded downtime info. + pub async fn all_downtime_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.blocktime.Query/AllDowntimeInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.blocktime.Query", "AllDowntimeInfo"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgUpdateDowntimeParams is the Msg/UpdateDowntimeParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateDowntimeParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the parameters to update. All parameters must be supplied. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateDowntimeParams { + const NAME: &'static str = "MsgUpdateDowntimeParams"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.MsgUpdateDowntimeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.MsgUpdateDowntimeParams".into() + } +} +/// MsgUpdateDowntimeParamsResponse is the Msg/UpdateDowntimeParams response +/// type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateDowntimeParamsResponse {} +impl ::prost::Name for MsgUpdateDowntimeParamsResponse { + const NAME: &'static str = "MsgUpdateDowntimeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.blocktime"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.blocktime.MsgUpdateDowntimeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.blocktime.MsgUpdateDowntimeParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// UpdateDowntimeParams updates the DowntimeParams in state. + pub async fn update_downtime_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.blocktime.Msg/UpdateDowntimeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.blocktime.Msg", "UpdateDowntimeParams"), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.bridge.rs b/v4-proto-rs/src/dydxprotocol.bridge.rs new file mode 100644 index 0000000000..43d0e28ca0 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.bridge.rs @@ -0,0 +1,1033 @@ +// This file is @generated by prost-build. +/// BridgeEvent is a recognized event from the Ethereum blockchain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BridgeEvent { + /// The unique id of the Ethereum event log. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The tokens bridged. + #[prost(message, optional, tag = "2")] + pub coin: ::core::option::Option, + /// The account address or module address to bridge to. + #[prost(string, tag = "3")] + pub address: ::prost::alloc::string::String, + /// The Ethereum block height of the event. + #[prost(uint64, tag = "4")] + pub eth_block_height: u64, +} +impl ::prost::Name for BridgeEvent { + const NAME: &'static str = "BridgeEvent"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.BridgeEvent".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.BridgeEvent".into() + } +} +/// BridgeEventInfo stores information about the most recently processed bridge +/// event. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BridgeEventInfo { + /// The next event id (the last processed id plus one) of the logs from the + /// Ethereum contract. + #[prost(uint32, tag = "1")] + pub next_id: u32, + /// The Ethereum block height of the most recently processed bridge event. + #[prost(uint64, tag = "2")] + pub eth_block_height: u64, +} +impl ::prost::Name for BridgeEventInfo { + const NAME: &'static str = "BridgeEventInfo"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.BridgeEventInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.BridgeEventInfo".into() + } +} +/// EventParams stores parameters about which events to recognize and which +/// tokens to mint. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventParams { + /// The denom of the token to mint. + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + /// The numerical chain ID of the Ethereum chain to query. + #[prost(uint64, tag = "2")] + pub eth_chain_id: u64, + /// The address of the Ethereum contract to monitor for logs. + #[prost(string, tag = "3")] + pub eth_address: ::prost::alloc::string::String, +} +impl ::prost::Name for EventParams { + const NAME: &'static str = "EventParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.EventParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.EventParams".into() + } +} +/// ProposeParams stores parameters for proposing to the module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProposeParams { + /// The maximum number of bridge events to propose per block. + /// Limits the number of events to propose in a single block + /// in-order to smooth out the flow of events. + #[prost(uint32, tag = "1")] + pub max_bridges_per_block: u32, + /// The minimum duration to wait between a finalized bridge and + /// proposing it. This allows other validators to have enough time to + /// also recognize its occurence. Therefore the bridge daemon should + /// pool for new finalized events at least as often as this parameter. + #[prost(message, optional, tag = "2")] + pub propose_delay_duration: ::core::option::Option<::prost_types::Duration>, + /// Do not propose any events if a [0, 1_000_000) random number generator + /// generates a number smaller than this number. + /// Setting this parameter to 1_000_000 means always skipping proposing events. + #[prost(uint32, tag = "3")] + pub skip_rate_ppm: u32, + /// Do not propose any events if the timestamp of the proposal block is + /// behind the proposers' wall-clock by at least this duration. + #[prost(message, optional, tag = "4")] + pub skip_if_block_delayed_by_duration: ::core::option::Option< + ::prost_types::Duration, + >, +} +impl ::prost::Name for ProposeParams { + const NAME: &'static str = "ProposeParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.ProposeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.ProposeParams".into() + } +} +/// SafetyParams stores safety parameters for the module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SafetyParams { + /// True if bridging is disabled. + #[prost(bool, tag = "1")] + pub is_disabled: bool, + /// The number of blocks that bridges accepted in-consensus will be pending + /// until the minted tokens are granted. + #[prost(uint32, tag = "2")] + pub delay_blocks: u32, +} +impl ::prost::Name for SafetyParams { + const NAME: &'static str = "SafetyParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.SafetyParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.SafetyParams".into() + } +} +/// GenesisState defines the bridge module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The parameters of the module. + #[prost(message, optional, tag = "1")] + pub event_params: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub propose_params: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub safety_params: ::core::option::Option, + /// Acknowledged event info that stores: + /// - the next event ID to be added to consensus. + /// - Ethereum block height of the most recently acknowledged bridge event. + #[prost(message, optional, tag = "4")] + pub acknowledged_event_info: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.GenesisState".into() + } +} +/// MsgAcknowledgeBridges is the Msg/AcknowledgeBridges request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAcknowledgeBridges { + /// The events to acknowledge. + #[prost(message, repeated, tag = "1")] + pub events: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgAcknowledgeBridges { + const NAME: &'static str = "MsgAcknowledgeBridges"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgAcknowledgeBridges".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgAcknowledgeBridges".into() + } +} +/// MsgAcknowledgeBridgesResponse is the Msg/AcknowledgeBridgesResponse response +/// type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAcknowledgeBridgesResponse {} +impl ::prost::Name for MsgAcknowledgeBridgesResponse { + const NAME: &'static str = "MsgAcknowledgeBridgesResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgAcknowledgeBridgesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgAcknowledgeBridgesResponse".into() + } +} +/// MsgCompleteBridge is the Msg/CompleteBridgeResponse request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCompleteBridge { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The event to complete. + #[prost(message, optional, tag = "2")] + pub event: ::core::option::Option, +} +impl ::prost::Name for MsgCompleteBridge { + const NAME: &'static str = "MsgCompleteBridge"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgCompleteBridge".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgCompleteBridge".into() + } +} +/// MsgCompleteBridgeResponse is the Msg/CompleteBridgeResponse response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCompleteBridgeResponse {} +impl ::prost::Name for MsgCompleteBridgeResponse { + const NAME: &'static str = "MsgCompleteBridgeResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgCompleteBridgeResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgCompleteBridgeResponse".into() + } +} +/// MsgUpdateEventParams is the Msg/UpdateEventParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateEventParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateEventParams { + const NAME: &'static str = "MsgUpdateEventParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateEventParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateEventParams".into() + } +} +/// MsgUpdateEventParamsResponse is the Msg/UpdateEventParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateEventParamsResponse {} +impl ::prost::Name for MsgUpdateEventParamsResponse { + const NAME: &'static str = "MsgUpdateEventParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateEventParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateEventParamsResponse".into() + } +} +/// MsgUpdateProposeParams is the Msg/UpdateProposeParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateProposeParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateProposeParams { + const NAME: &'static str = "MsgUpdateProposeParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateProposeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateProposeParams".into() + } +} +/// MsgUpdateProposeParamsResponse is the Msg/UpdateProposeParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateProposeParamsResponse {} +impl ::prost::Name for MsgUpdateProposeParamsResponse { + const NAME: &'static str = "MsgUpdateProposeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateProposeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateProposeParamsResponse".into() + } +} +/// MsgUpdateSafetyParams is the Msg/UpdateSafetyParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateSafetyParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateSafetyParams { + const NAME: &'static str = "MsgUpdateSafetyParams"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateSafetyParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateSafetyParams".into() + } +} +/// MsgUpdateSafetyParamsResponse is the Msg/UpdateSafetyParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateSafetyParamsResponse {} +impl ::prost::Name for MsgUpdateSafetyParamsResponse { + const NAME: &'static str = "MsgUpdateSafetyParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.MsgUpdateSafetyParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.MsgUpdateSafetyParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// AcknowledgeBridges acknowledges bridges and sets them to complete at a + /// later block. + pub async fn acknowledge_bridges( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Msg/AcknowledgeBridges", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.bridge.Msg", "AcknowledgeBridges"), + ); + self.inner.unary(req, path, codec).await + } + /// CompleteBridge finalizes a bridge by minting coins to an address. + pub async fn complete_bridge( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Msg/CompleteBridge", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.bridge.Msg", "CompleteBridge")); + self.inner.unary(req, path, codec).await + } + /// UpdateEventParams updates the EventParams in state. + pub async fn update_event_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Msg/UpdateEventParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.bridge.Msg", "UpdateEventParams")); + self.inner.unary(req, path, codec).await + } + /// UpdateProposeParams updates the ProposeParams in state. + pub async fn update_propose_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Msg/UpdateProposeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.bridge.Msg", "UpdateProposeParams"), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateSafetyParams updates the SafetyParams in state. + pub async fn update_safety_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Msg/UpdateSafetyParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.bridge.Msg", "UpdateSafetyParams"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// QueryEventParamsRequest is a request type for the EventParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEventParamsRequest {} +impl ::prost::Name for QueryEventParamsRequest { + const NAME: &'static str = "QueryEventParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryEventParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryEventParamsRequest".into() + } +} +/// QueryEventParamsResponse is a response type for the EventParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEventParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryEventParamsResponse { + const NAME: &'static str = "QueryEventParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryEventParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryEventParamsResponse".into() + } +} +/// QueryProposeParamsRequest is a request type for the ProposeParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryProposeParamsRequest {} +impl ::prost::Name for QueryProposeParamsRequest { + const NAME: &'static str = "QueryProposeParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryProposeParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryProposeParamsRequest".into() + } +} +/// QueryProposeParamsResponse is a response type for the ProposeParams RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryProposeParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryProposeParamsResponse { + const NAME: &'static str = "QueryProposeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryProposeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryProposeParamsResponse".into() + } +} +/// QuerySafetyParamsRequest is a request type for the SafetyParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySafetyParamsRequest {} +impl ::prost::Name for QuerySafetyParamsRequest { + const NAME: &'static str = "QuerySafetyParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QuerySafetyParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QuerySafetyParamsRequest".into() + } +} +/// QuerySafetyParamsResponse is a response type for the SafetyParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySafetyParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QuerySafetyParamsResponse { + const NAME: &'static str = "QuerySafetyParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QuerySafetyParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QuerySafetyParamsResponse".into() + } +} +/// QueryAcknowledgedEventInfoRequest is a request type for the +/// AcknowledgedEventInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAcknowledgedEventInfoRequest {} +impl ::prost::Name for QueryAcknowledgedEventInfoRequest { + const NAME: &'static str = "QueryAcknowledgedEventInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryAcknowledgedEventInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryAcknowledgedEventInfoRequest".into() + } +} +/// QueryAcknowledgedEventInfoResponse is a response type for the +/// AcknowledgedEventInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAcknowledgedEventInfoResponse { + #[prost(message, optional, tag = "1")] + pub info: ::core::option::Option, +} +impl ::prost::Name for QueryAcknowledgedEventInfoResponse { + const NAME: &'static str = "QueryAcknowledgedEventInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryAcknowledgedEventInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryAcknowledgedEventInfoResponse".into() + } +} +/// QueryRecognizedEventInfoRequest is a request type for the +/// RecognizedEventInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryRecognizedEventInfoRequest {} +impl ::prost::Name for QueryRecognizedEventInfoRequest { + const NAME: &'static str = "QueryRecognizedEventInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryRecognizedEventInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryRecognizedEventInfoRequest".into() + } +} +/// QueryRecognizedEventInfoResponse is a response type for the +/// RecognizedEventInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryRecognizedEventInfoResponse { + #[prost(message, optional, tag = "1")] + pub info: ::core::option::Option, +} +impl ::prost::Name for QueryRecognizedEventInfoResponse { + const NAME: &'static str = "QueryRecognizedEventInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryRecognizedEventInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryRecognizedEventInfoResponse".into() + } +} +/// QueryDelayedCompleteBridgeMessagesRequest is a request type for the +/// DelayedCompleteBridgeMessages RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryDelayedCompleteBridgeMessagesRequest { + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryDelayedCompleteBridgeMessagesRequest { + const NAME: &'static str = "QueryDelayedCompleteBridgeMessagesRequest"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryDelayedCompleteBridgeMessagesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryDelayedCompleteBridgeMessagesRequest".into() + } +} +/// QueryDelayedCompleteBridgeMessagesResponse is a response type for the +/// DelayedCompleteBridgeMessages RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryDelayedCompleteBridgeMessagesResponse { + #[prost(message, repeated, tag = "1")] + pub messages: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryDelayedCompleteBridgeMessagesResponse { + const NAME: &'static str = "QueryDelayedCompleteBridgeMessagesResponse"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.QueryDelayedCompleteBridgeMessagesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.QueryDelayedCompleteBridgeMessagesResponse".into() + } +} +/// DelayedCompleteBridgeMessage is a message type for the response of +/// DelayedCompleteBridgeMessages RPC method. It contains the message +/// and the block height at which it will execute. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DelayedCompleteBridgeMessage { + #[prost(message, optional, tag = "1")] + pub message: ::core::option::Option, + #[prost(uint32, tag = "2")] + pub block_height: u32, +} +impl ::prost::Name for DelayedCompleteBridgeMessage { + const NAME: &'static str = "DelayedCompleteBridgeMessage"; + const PACKAGE: &'static str = "dydxprotocol.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.bridge.DelayedCompleteBridgeMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.bridge.DelayedCompleteBridgeMessage".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the EventParams. + pub async fn event_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/EventParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.bridge.Query", "EventParams")); + self.inner.unary(req, path, codec).await + } + /// Queries the ProposeParams. + pub async fn propose_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/ProposeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.bridge.Query", "ProposeParams")); + self.inner.unary(req, path, codec).await + } + /// Queries the SafetyParams. + pub async fn safety_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/SafetyParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.bridge.Query", "SafetyParams")); + self.inner.unary(req, path, codec).await + } + /// Queries the AcknowledgedEventInfo. + /// An "acknowledged" event is one that is in-consensus and has been stored + /// in-state. + pub async fn acknowledged_event_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/AcknowledgedEventInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.bridge.Query", "AcknowledgedEventInfo"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the RecognizedEventInfo. + /// A "recognized" event is one that is finalized on the Ethereum blockchain + /// and has been identified by the queried node. It is not yet in-consensus. + pub async fn recognized_event_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/RecognizedEventInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.bridge.Query", "RecognizedEventInfo"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries all `MsgCompleteBridge` messages that are delayed (not yet + /// executed) and corresponding block heights at which they will execute. + pub async fn delayed_complete_bridge_messages( + &mut self, + request: impl tonic::IntoRequest< + super::QueryDelayedCompleteBridgeMessagesRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.bridge.Query/DelayedCompleteBridgeMessages", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.bridge.Query", + "DelayedCompleteBridgeMessages", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.clob.rs b/v4-proto-rs/src/dydxprotocol.clob.rs new file mode 100644 index 0000000000..c8c7008c1c --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.clob.rs @@ -0,0 +1,2984 @@ +// This file is @generated by prost-build. +/// Defines the block rate limits for CLOB specific operations. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockRateLimitConfiguration { + /// How many short term order attempts (successful and failed) are allowed for + /// an account per N blocks. Note that the rate limits are applied + /// in an AND fashion such that an order placement must pass all rate limit + /// configurations. + /// + /// Specifying 0 values disables this rate limit. + /// Deprecated in favor of `max_short_term_orders_and_cancels_per_n_blocks` + /// for v5.x onwards. + #[deprecated] + #[prost(message, repeated, tag = "1")] + pub max_short_term_orders_per_n_blocks: ::prost::alloc::vec::Vec< + MaxPerNBlocksRateLimit, + >, + /// How many stateful order attempts (successful and failed) are allowed for + /// an account per N blocks. Note that the rate limits are applied + /// in an AND fashion such that an order placement must pass all rate limit + /// configurations. + /// + /// Specifying 0 values disables this rate limit. + #[prost(message, repeated, tag = "2")] + pub max_stateful_orders_per_n_blocks: ::prost::alloc::vec::Vec< + MaxPerNBlocksRateLimit, + >, + /// How many short term order cancellation attempts (successful and failed) are + /// allowed for an account per N blocks. Note that the rate limits are + /// applied in an AND fashion such that an order cancellation must pass all + /// rate limit configurations. + /// + /// Specifying 0 values disables this rate limit. + /// Deprecated in favor of `max_short_term_orders_and_cancels_per_n_blocks` + /// for v5.x onwards. + #[deprecated] + #[prost(message, repeated, tag = "3")] + pub max_short_term_order_cancellations_per_n_blocks: ::prost::alloc::vec::Vec< + MaxPerNBlocksRateLimit, + >, + /// How many short term order place and cancel attempts (successful and failed) + /// are allowed for an account per N blocks. Note that the rate limits are + /// applied in an AND fashion such that an order placement must pass all rate + /// limit configurations. + /// + /// Specifying 0 values disables this rate limit. + #[prost(message, repeated, tag = "4")] + pub max_short_term_orders_and_cancels_per_n_blocks: ::prost::alloc::vec::Vec< + MaxPerNBlocksRateLimit, + >, +} +impl ::prost::Name for BlockRateLimitConfiguration { + const NAME: &'static str = "BlockRateLimitConfiguration"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.BlockRateLimitConfiguration".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.BlockRateLimitConfiguration".into() + } +} +/// Defines a rate limit over a specific number of blocks. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MaxPerNBlocksRateLimit { + /// How many blocks the rate limit is over. + /// Specifying 0 is invalid. + #[prost(uint32, tag = "1")] + pub num_blocks: u32, + /// What the limit is for `num_blocks`. + /// Specifying 0 is invalid. + #[prost(uint32, tag = "2")] + pub limit: u32, +} +impl ::prost::Name for MaxPerNBlocksRateLimit { + const NAME: &'static str = "MaxPerNBlocksRateLimit"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MaxPerNBlocksRateLimit".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MaxPerNBlocksRateLimit".into() + } +} +/// PerpetualClobMetadata contains metadata for a `ClobPair` +/// representing a Perpetual product. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualClobMetadata { + /// Id of the Perpetual the CLOB allows trading of. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, +} +impl ::prost::Name for PerpetualClobMetadata { + const NAME: &'static str = "PerpetualClobMetadata"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.PerpetualClobMetadata".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.PerpetualClobMetadata".into() + } +} +/// PerpetualClobMetadata contains metadata for a `ClobPair` +/// representing a Spot product. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpotClobMetadata { + /// Id of the base Asset in the trading pair. + #[prost(uint32, tag = "1")] + pub base_asset_id: u32, + /// Id of the quote Asset in the trading pair. + #[prost(uint32, tag = "2")] + pub quote_asset_id: u32, +} +impl ::prost::Name for SpotClobMetadata { + const NAME: &'static str = "SpotClobMetadata"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.SpotClobMetadata".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.SpotClobMetadata".into() + } +} +/// ClobPair represents a single CLOB pair for a given product +/// in state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClobPair { + /// ID of the orderbook that stores all resting liquidity for this CLOB. + #[prost(uint32, tag = "1")] + pub id: u32, + /// Minimum increment in the size of orders on the CLOB, in base quantums. + #[prost(uint64, tag = "4")] + pub step_base_quantums: u64, + /// Defines the tick size of the orderbook by defining how many subticks + /// are in one tick. That is, the subticks of any valid order must be a + /// multiple of this value. Generally this value should start `>= 100`to + /// allow room for decreasing it. + #[prost(uint32, tag = "5")] + pub subticks_per_tick: u32, + /// `10^Exponent` gives the number of QuoteQuantums traded per BaseQuantum + /// per Subtick. + #[prost(sint32, tag = "6")] + pub quantum_conversion_exponent: i32, + #[prost(enumeration = "clob_pair::Status", tag = "7")] + pub status: i32, + /// Product-specific metadata. Perpetual CLOBs will have + /// PerpetualClobMetadata, and Spot CLOBs will have SpotClobMetadata. + #[prost(oneof = "clob_pair::Metadata", tags = "2, 3")] + pub metadata: ::core::option::Option, +} +/// Nested message and enum types in `ClobPair`. +pub mod clob_pair { + /// Status of the CLOB. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Status { + /// Default value. This value is invalid and unused. + Unspecified = 0, + /// STATUS_ACTIVE represents an active clob pair. + Active = 1, + /// STATUS_PAUSED behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + Paused = 2, + /// STATUS_CANCEL_ONLY behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + CancelOnly = 3, + /// STATUS_POST_ONLY behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + PostOnly = 4, + /// STATUS_INITIALIZING represents a newly-added clob pair. + /// Clob pairs in this state only accept orders which are + /// both short-term and post-only. + Initializing = 5, + /// STATUS_FINAL_SETTLEMENT represents a clob pair which is deactivated + /// and trading has ceased. All open positions will be closed by the + /// protocol. Open stateful orders will be cancelled. Open short-term + /// orders will be left to expire. + FinalSettlement = 6, + } + impl Status { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Status::Unspecified => "STATUS_UNSPECIFIED", + Status::Active => "STATUS_ACTIVE", + Status::Paused => "STATUS_PAUSED", + Status::CancelOnly => "STATUS_CANCEL_ONLY", + Status::PostOnly => "STATUS_POST_ONLY", + Status::Initializing => "STATUS_INITIALIZING", + Status::FinalSettlement => "STATUS_FINAL_SETTLEMENT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "STATUS_ACTIVE" => Some(Self::Active), + "STATUS_PAUSED" => Some(Self::Paused), + "STATUS_CANCEL_ONLY" => Some(Self::CancelOnly), + "STATUS_POST_ONLY" => Some(Self::PostOnly), + "STATUS_INITIALIZING" => Some(Self::Initializing), + "STATUS_FINAL_SETTLEMENT" => Some(Self::FinalSettlement), + _ => None, + } + } + } + /// Product-specific metadata. Perpetual CLOBs will have + /// PerpetualClobMetadata, and Spot CLOBs will have SpotClobMetadata. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Metadata { + #[prost(message, tag = "2")] + PerpetualClobMetadata(super::PerpetualClobMetadata), + #[prost(message, tag = "3")] + SpotClobMetadata(super::SpotClobMetadata), + } +} +impl ::prost::Name for ClobPair { + const NAME: &'static str = "ClobPair"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ClobPair".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ClobPair".into() + } +} +/// Defines the set of equity tiers to limit how many open orders +/// a subaccount is allowed to have. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EquityTierLimitConfiguration { + /// How many short term stateful orders are allowed per equity tier. + /// Specifying 0 values disables this limit. + #[prost(message, repeated, tag = "1")] + pub short_term_order_equity_tiers: ::prost::alloc::vec::Vec, + /// How many open stateful orders are allowed per equity tier. + /// Specifying 0 values disables this limit. + #[prost(message, repeated, tag = "2")] + pub stateful_order_equity_tiers: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for EquityTierLimitConfiguration { + const NAME: &'static str = "EquityTierLimitConfiguration"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.EquityTierLimitConfiguration".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.EquityTierLimitConfiguration".into() + } +} +/// Defines an equity tier limit. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EquityTierLimit { + /// The total net collateral in USDC quote quantums of equity required. + #[prost(bytes = "vec", tag = "1")] + pub usd_tnc_required: ::prost::alloc::vec::Vec, + /// What the limit is for `usd_tnc_required`. + #[prost(uint32, tag = "2")] + pub limit: u32, +} +impl ::prost::Name for EquityTierLimit { + const NAME: &'static str = "EquityTierLimit"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.EquityTierLimit".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.EquityTierLimit".into() + } +} +/// LiquidationsConfig stores all configurable fields related to liquidations. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidationsConfig { + /// The maximum liquidation fee (in parts-per-million). This fee goes + /// 100% to the insurance fund. + #[prost(uint32, tag = "1")] + pub max_liquidation_fee_ppm: u32, + /// Limits around how much of a single position can be liquidated + /// within a single block. + #[prost(message, optional, tag = "2")] + pub position_block_limits: ::core::option::Option, + /// Limits around how many quote quantums from a single subaccount can + /// be liquidated within a single block. + #[prost(message, optional, tag = "3")] + pub subaccount_block_limits: ::core::option::Option, + /// Config about how the fillable-price spread from the oracle price + /// increases based on the adjusted bankruptcy rating of the subaccount. + #[prost(message, optional, tag = "4")] + pub fillable_price_config: ::core::option::Option, +} +impl ::prost::Name for LiquidationsConfig { + const NAME: &'static str = "LiquidationsConfig"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.LiquidationsConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.LiquidationsConfig".into() + } +} +/// PositionBlockLimits stores all configurable fields related to limits +/// around how much of a single position can be liquidated within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PositionBlockLimits { + /// The minimum amount of quantums to liquidate for each message (in + /// quote quantums). + /// Overridden by the maximum size of the position. + #[prost(uint64, tag = "1")] + pub min_position_notional_liquidated: u64, + /// The maximum portion of the position liquidated (in parts-per- + /// million). Overridden by min_position_notional_liquidated. + #[prost(uint32, tag = "2")] + pub max_position_portion_liquidated_ppm: u32, +} +impl ::prost::Name for PositionBlockLimits { + const NAME: &'static str = "PositionBlockLimits"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.PositionBlockLimits".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.PositionBlockLimits".into() + } +} +/// SubaccountBlockLimits stores all configurable fields related to limits +/// around how many quote quantums from a single subaccount can +/// be liquidated within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountBlockLimits { + /// The maximum notional amount that a single subaccount can have + /// liquidated (in quote quantums) per block. + #[prost(uint64, tag = "1")] + pub max_notional_liquidated: u64, + /// The maximum insurance-fund payout amount for a given subaccount + /// per block. I.e. how much it can cover for that subaccount. + #[prost(uint64, tag = "2")] + pub max_quantums_insurance_lost: u64, +} +impl ::prost::Name for SubaccountBlockLimits { + const NAME: &'static str = "SubaccountBlockLimits"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.SubaccountBlockLimits".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.SubaccountBlockLimits".into() + } +} +/// FillablePriceConfig stores all configurable fields related to calculating +/// the fillable price for liquidating a position. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FillablePriceConfig { + /// The rate at which the Adjusted Bankruptcy Rating increases. + #[prost(uint32, tag = "1")] + pub bankruptcy_adjustment_ppm: u32, + /// The maximum value that the liquidation spread can take, as + /// a ratio against the position's maintenance margin. + #[prost(uint32, tag = "2")] + pub spread_to_maintenance_margin_ratio_ppm: u32, +} +impl ::prost::Name for FillablePriceConfig { + const NAME: &'static str = "FillablePriceConfig"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.FillablePriceConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.FillablePriceConfig".into() + } +} +/// GenesisState defines the clob module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub clob_pairs: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub liquidations_config: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub block_rate_limit_config: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub equity_tier_limit_config: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.GenesisState".into() + } +} +/// PerpetualLiquidationInfo holds information about a liquidation that occurred +/// for a position held by a subaccount. +/// Note this proto is defined to make it easier to hash +/// the metadata of a liquidation, and is never written to state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualLiquidationInfo { + /// The id of the subaccount that got liquidated/deleveraged or was deleveraged + /// onto. + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// The id of the perpetual involved. + #[prost(uint32, tag = "2")] + pub perpetual_id: u32, +} +impl ::prost::Name for PerpetualLiquidationInfo { + const NAME: &'static str = "PerpetualLiquidationInfo"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.PerpetualLiquidationInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.PerpetualLiquidationInfo".into() + } +} +/// SubaccountLiquidationInfo holds liquidation information per-subaccount in the +/// current block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountLiquidationInfo { + /// An unsorted list of unique perpetual IDs that the subaccount has previously + /// liquidated. + #[prost(uint32, repeated, tag = "1")] + pub perpetuals_liquidated: ::prost::alloc::vec::Vec, + /// The notional value (in quote quantums, determined by the oracle price) of + /// all positions liquidated for this subaccount. + #[prost(uint64, tag = "2")] + pub notional_liquidated: u64, + /// The amount of funds that the insurance fund has lost + /// covering this subaccount. + #[prost(uint64, tag = "3")] + pub quantums_insurance_lost: u64, +} +impl ::prost::Name for SubaccountLiquidationInfo { + const NAME: &'static str = "SubaccountLiquidationInfo"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.SubaccountLiquidationInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.SubaccountLiquidationInfo".into() + } +} +/// SubaccountOpenPositionInfo holds information about open positions for a +/// perpetual. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountOpenPositionInfo { + /// The id of the perpetual. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The ids of the subaccounts with long positions. + #[prost(message, repeated, tag = "2")] + pub subaccounts_with_long_position: ::prost::alloc::vec::Vec< + super::subaccounts::SubaccountId, + >, + /// The ids of the subaccounts with short positions. + #[prost(message, repeated, tag = "3")] + pub subaccounts_with_short_position: ::prost::alloc::vec::Vec< + super::subaccounts::SubaccountId, + >, +} +impl ::prost::Name for SubaccountOpenPositionInfo { + const NAME: &'static str = "SubaccountOpenPositionInfo"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.SubaccountOpenPositionInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.SubaccountOpenPositionInfo".into() + } +} +/// OrderId refers to a single order belonging to a Subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderId { + /// The subaccount ID that opened this order. + /// Note that this field has `gogoproto.nullable = false` so that it is + /// generated as a value instead of a pointer. This is because the `OrderId` + /// proto is used as a key within maps, and map comparisons will compare + /// pointers for equality (when the desired behavior is to compare the values). + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// The client ID of this order, unique with respect to the specific + /// sub account (I.E., the same subaccount can't have two orders with + /// the same ClientId). + #[prost(fixed32, tag = "2")] + pub client_id: u32, + /// order_flags represent order flags for the order. This field is invalid if + /// it's greater than 127 (larger than one byte). Each bit in the first byte + /// represents a different flag. Currently only two flags are supported. + /// + /// Starting from the bit after the most MSB (note that the MSB is used in + /// proto varint encoding, and therefore cannot be used): Bit 1 is set if this + /// order is a Long-Term order (0x40, or 64 as a uint8). Bit 2 is set if this + /// order is a Conditional order (0x20, or 32 as a uint8). + /// + /// If neither bit is set, the order is assumed to be a Short-Term order. + /// + /// If both bits are set or bits other than the 2nd and 3rd are set, the order + /// ID is invalid. + #[prost(uint32, tag = "3")] + pub order_flags: u32, + /// ID of the CLOB the order is created for. + #[prost(uint32, tag = "4")] + pub clob_pair_id: u32, +} +impl ::prost::Name for OrderId { + const NAME: &'static str = "OrderId"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OrderId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OrderId".into() + } +} +/// OrdersFilledDuringLatestBlock represents a list of `OrderIds` that were +/// filled by any non-zero amount in the latest block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrdersFilledDuringLatestBlock { + /// A list of unique order_ids that were filled by any non-zero amount in the + /// latest block. + #[prost(message, repeated, tag = "1")] + pub order_ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for OrdersFilledDuringLatestBlock { + const NAME: &'static str = "OrdersFilledDuringLatestBlock"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OrdersFilledDuringLatestBlock".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OrdersFilledDuringLatestBlock".into() + } +} +/// PotentiallyPrunableOrders represents a list of orders that may be prunable +/// from state at a future block height. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PotentiallyPrunableOrders { + /// A list of unique order_ids that may potentially be pruned from state at a + /// future block height. + #[prost(message, repeated, tag = "1")] + pub order_ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for PotentiallyPrunableOrders { + const NAME: &'static str = "PotentiallyPrunableOrders"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.PotentiallyPrunableOrders".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.PotentiallyPrunableOrders".into() + } +} +/// OrderFillState represents the fill amount of an order according to on-chain +/// state. This proto includes both the current on-chain fill amount of the +/// order, as well as the block at which this information can be pruned from +/// state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderFillState { + /// The current fillAmount of the order according to on-chain state. + #[prost(uint64, tag = "1")] + pub fill_amount: u64, + /// The block height at which the fillAmount state for this order can be + /// pruned. + #[prost(uint32, tag = "2")] + pub prunable_block_height: u32, +} +impl ::prost::Name for OrderFillState { + const NAME: &'static str = "OrderFillState"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OrderFillState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OrderFillState".into() + } +} +/// StatefulOrderTimeSliceValue represents the type of the value of the +/// `StatefulOrdersTimeSlice` in state. The `StatefulOrdersTimeSlice` +/// in state consists of key/value pairs where the keys are UTF-8-encoded +/// `RFC3339NANO` timestamp strings with right-padded zeroes and no +/// time zone info, and the values are of type `StatefulOrderTimeSliceValue`. +/// This `StatefulOrderTimeSliceValue` in state is used for managing stateful +/// order expiration. Stateful order expirations can be for either long term +/// or conditional orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatefulOrderTimeSliceValue { + /// A unique list of order_ids that expire at this timestamp, sorted in + /// ascending order by block height and transaction index of each stateful + /// order. + #[prost(message, repeated, tag = "1")] + pub order_ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for StatefulOrderTimeSliceValue { + const NAME: &'static str = "StatefulOrderTimeSliceValue"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StatefulOrderTimeSliceValue".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StatefulOrderTimeSliceValue".into() + } +} +/// LongTermOrderPlacement represents the placement of a stateful order in +/// state. It stores the stateful order itself and the `BlockHeight` and +/// `TransactionIndex` at which the order was placed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LongTermOrderPlacement { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + /// The block height and transaction index at which the order was placed. + /// Used for ordering by time priority when the chain is restarted. + #[prost(message, optional, tag = "2")] + pub placement_index: ::core::option::Option, +} +impl ::prost::Name for LongTermOrderPlacement { + const NAME: &'static str = "LongTermOrderPlacement"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.LongTermOrderPlacement".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.LongTermOrderPlacement".into() + } +} +/// ConditionalOrderPlacement represents the placement of a conditional order in +/// state. It stores the stateful order itself, the `BlockHeight` and +/// `TransactionIndex` at which the order was placed and triggered. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConditionalOrderPlacement { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + /// The block height and transaction index at which the order was placed. + #[prost(message, optional, tag = "2")] + pub placement_index: ::core::option::Option, + /// The block height and transaction index at which the order was triggered. + /// Set to be nil if the transaction has not been triggered. + /// Used for ordering by time priority when the chain is restarted. + #[prost(message, optional, tag = "3")] + pub trigger_index: ::core::option::Option, +} +impl ::prost::Name for ConditionalOrderPlacement { + const NAME: &'static str = "ConditionalOrderPlacement"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ConditionalOrderPlacement".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ConditionalOrderPlacement".into() + } +} +/// Order represents a single order belonging to a `Subaccount` +/// for a particular `ClobPair`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Order { + /// The unique ID of this order. Meant to be unique across all orders. + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, + #[prost(enumeration = "order::Side", tag = "2")] + pub side: i32, + /// The size of this order in base quantums. Must be a multiple of + /// `ClobPair.StepBaseQuantums` (where `ClobPair.Id = orderId.ClobPairId`). + #[prost(uint64, tag = "3")] + pub quantums: u64, + /// The price level that this order will be placed at on the orderbook, + /// in subticks. Must be a multiple of ClobPair.SubticksPerTick + /// (where `ClobPair.Id = orderId.ClobPairId`). + #[prost(uint64, tag = "4")] + pub subticks: u64, + /// The time in force of this order. + #[prost(enumeration = "order::TimeInForce", tag = "7")] + pub time_in_force: i32, + /// Enforces that the order can only reduce the size of an existing position. + /// If a ReduceOnly order would change the side of the existing position, + /// its size is reduced to that of the remaining size of the position. + /// If existing orders on the book with ReduceOnly + /// would already close the position, the least aggressive (out-of-the-money) + /// ReduceOnly orders are resized and canceled first. + #[prost(bool, tag = "8")] + pub reduce_only: bool, + /// Set of bit flags set arbitrarily by clients and ignored by the protocol. + /// Used by indexer to infer information about a placed order. + #[prost(uint32, tag = "9")] + pub client_metadata: u32, + #[prost(enumeration = "order::ConditionType", tag = "10")] + pub condition_type: i32, + /// conditional_order_trigger_subticks represents the price at which this order + /// will be triggered. If the condition_type is CONDITION_TYPE_UNSPECIFIED, + /// this value is enforced to be 0. If this value is nonzero, condition_type + /// cannot be CONDITION_TYPE_UNSPECIFIED. Value is in subticks. + /// Must be a multiple of ClobPair.SubticksPerTick (where `ClobPair.Id = + /// orderId.ClobPairId`). + #[prost(uint64, tag = "11")] + pub conditional_order_trigger_subticks: u64, + /// Information about when the order expires. + #[prost(oneof = "order::GoodTilOneof", tags = "5, 6")] + pub good_til_oneof: ::core::option::Option, +} +/// Nested message and enum types in `Order`. +pub mod order { + /// Represents the side of the orderbook the order will be placed on. + /// Note that Side.SIDE_UNSPECIFIED is an invalid order and cannot be + /// placed on the orderbook. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Side { + /// Default value. This value is invalid and unused. + Unspecified = 0, + /// SIDE_BUY is used to represent a BUY order. + Buy = 1, + /// SIDE_SELL is used to represent a SELL order. + Sell = 2, + } + impl Side { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Side::Unspecified => "SIDE_UNSPECIFIED", + Side::Buy => "SIDE_BUY", + Side::Sell => "SIDE_SELL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SIDE_UNSPECIFIED" => Some(Self::Unspecified), + "SIDE_BUY" => Some(Self::Buy), + "SIDE_SELL" => Some(Self::Sell), + _ => None, + } + } + } + /// TimeInForce indicates how long an order will remain active before it + /// is executed or expires. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum TimeInForce { + /// TIME_IN_FORCE_UNSPECIFIED represents the default behavior where an + /// order will first match with existing orders on the book, and any + /// remaining size will be added to the book as a maker order. + Unspecified = 0, + /// TIME_IN_FORCE_IOC enforces that an order only be matched with + /// maker orders on the book. If the order has remaining size after + /// matching with existing orders on the book, the remaining size + /// is not placed on the book. + Ioc = 1, + /// TIME_IN_FORCE_POST_ONLY enforces that an order only be placed + /// on the book as a maker order. Note this means that validators will cancel + /// any newly-placed post only orders that would cross with other maker + /// orders. + PostOnly = 2, + /// TIME_IN_FORCE_FILL_OR_KILL enforces that an order will either be filled + /// completely and immediately by maker orders on the book or canceled if the + /// entire amount can‘t be matched. + FillOrKill = 3, + } + impl TimeInForce { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + TimeInForce::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", + TimeInForce::Ioc => "TIME_IN_FORCE_IOC", + TimeInForce::PostOnly => "TIME_IN_FORCE_POST_ONLY", + TimeInForce::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TIME_IN_FORCE_UNSPECIFIED" => Some(Self::Unspecified), + "TIME_IN_FORCE_IOC" => Some(Self::Ioc), + "TIME_IN_FORCE_POST_ONLY" => Some(Self::PostOnly), + "TIME_IN_FORCE_FILL_OR_KILL" => Some(Self::FillOrKill), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ConditionType { + /// CONDITION_TYPE_UNSPECIFIED represents the default behavior where an + /// order will be placed immediately on the orderbook. + Unspecified = 0, + /// CONDITION_TYPE_STOP_LOSS represents a stop order. A stop order will + /// trigger when the oracle price moves at or above the trigger price for + /// buys, and at or below the trigger price for sells. + StopLoss = 1, + /// CONDITION_TYPE_TAKE_PROFIT represents a take profit order. A take profit + /// order will trigger when the oracle price moves at or below the trigger + /// price for buys and at or above the trigger price for sells. + TakeProfit = 2, + } + impl ConditionType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ConditionType::Unspecified => "CONDITION_TYPE_UNSPECIFIED", + ConditionType::StopLoss => "CONDITION_TYPE_STOP_LOSS", + ConditionType::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CONDITION_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "CONDITION_TYPE_STOP_LOSS" => Some(Self::StopLoss), + "CONDITION_TYPE_TAKE_PROFIT" => Some(Self::TakeProfit), + _ => None, + } + } + } + /// Information about when the order expires. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum GoodTilOneof { + /// The last block this order can be executed at (after which it will be + /// unfillable). Used only for Short-Term orders. If this value is non-zero + /// then the order is assumed to be a Short-Term order. + #[prost(uint32, tag = "5")] + GoodTilBlock(u32), + /// good_til_block_time represents the unix timestamp (in seconds) at which a + /// stateful order will be considered expired. The + /// good_til_block_time is always evaluated against the previous block's + /// `BlockTime` instead of the block in which the order is committed. If this + /// value is non-zero then the order is assumed to be a stateful or + /// conditional order. + #[prost(fixed32, tag = "6")] + GoodTilBlockTime(u32), + } +} +impl ::prost::Name for Order { + const NAME: &'static str = "Order"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.Order".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.Order".into() + } +} +/// TransactionOrdering represents a unique location in the block where a +/// transaction was placed. This proto includes both block height and the +/// transaction index that the specific transaction was placed. This information +/// is used for ordering by time priority when the chain is restarted. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionOrdering { + /// Block height in which the transaction was placed. + #[prost(uint32, tag = "1")] + pub block_height: u32, + /// Within the block, the unique transaction index. + #[prost(uint32, tag = "2")] + pub transaction_index: u32, +} +impl ::prost::Name for TransactionOrdering { + const NAME: &'static str = "TransactionOrdering"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.TransactionOrdering".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.TransactionOrdering".into() + } +} +/// ClobMatch represents an operations queue entry around all different types +/// of matches, specifically regular matches, liquidation matches, and +/// deleveraging matches. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClobMatch { + /// The match type that this message includes. + #[prost(oneof = "clob_match::Match", tags = "1, 2, 3")] + pub r#match: ::core::option::Option, +} +/// Nested message and enum types in `ClobMatch`. +pub mod clob_match { + /// The match type that this message includes. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Match { + #[prost(message, tag = "1")] + MatchOrders(super::MatchOrders), + #[prost(message, tag = "2")] + MatchPerpetualLiquidation(super::MatchPerpetualLiquidation), + #[prost(message, tag = "3")] + MatchPerpetualDeleveraging(super::MatchPerpetualDeleveraging), + } +} +impl ::prost::Name for ClobMatch { + const NAME: &'static str = "ClobMatch"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ClobMatch".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ClobMatch".into() + } +} +/// MakerFill represents the filled amount of a matched maker order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MakerFill { + /// The filled amount of the matched maker order, in base quantums. + /// TODO(CLOB-571): update to use SerializableInt. + #[prost(uint64, tag = "1")] + pub fill_amount: u64, + /// The `OrderId` of the matched maker order. + #[prost(message, optional, tag = "2")] + pub maker_order_id: ::core::option::Option, +} +impl ::prost::Name for MakerFill { + const NAME: &'static str = "MakerFill"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MakerFill".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MakerFill".into() + } +} +/// MatchOrders is an injected message used for matching orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MatchOrders { + /// The `OrderId` of the taker order. + #[prost(message, optional, tag = "1")] + pub taker_order_id: ::core::option::Option, + /// An ordered list of fills created by this taker order. + #[prost(message, repeated, tag = "2")] + pub fills: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MatchOrders { + const NAME: &'static str = "MatchOrders"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MatchOrders".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MatchOrders".into() + } +} +/// MatchPerpetualLiquidation is an injected message used for liquidating a +/// subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MatchPerpetualLiquidation { + /// ID of the subaccount that was liquidated. + #[prost(message, optional, tag = "1")] + pub liquidated: ::core::option::Option, + /// The ID of the clob pair involved in the liquidation. + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// The ID of the perpetual involved in the liquidation. + #[prost(uint32, tag = "3")] + pub perpetual_id: u32, + /// The total size of the liquidation order including any unfilled size. + #[prost(uint64, tag = "4")] + pub total_size: u64, + /// `true` if liquidating a short position, `false` otherwise. + #[prost(bool, tag = "5")] + pub is_buy: bool, + /// An ordered list of fills created by this liquidation. + #[prost(message, repeated, tag = "6")] + pub fills: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MatchPerpetualLiquidation { + const NAME: &'static str = "MatchPerpetualLiquidation"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MatchPerpetualLiquidation".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MatchPerpetualLiquidation".into() + } +} +/// MatchPerpetualDeleveraging is an injected message used for deleveraging a +/// subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MatchPerpetualDeleveraging { + /// ID of the subaccount that was liquidated. + #[prost(message, optional, tag = "1")] + pub liquidated: ::core::option::Option, + /// The ID of the perpetual that was liquidated. + #[prost(uint32, tag = "2")] + pub perpetual_id: u32, + /// An ordered list of fills created by this liquidation. + #[prost(message, repeated, tag = "3")] + pub fills: ::prost::alloc::vec::Vec, + /// Flag denoting whether the deleveraging operation was for the purpose + /// of final settlement. Final settlement matches are at the oracle price, + /// whereas deleveraging happens at the bankruptcy price of the deleveraged + /// subaccount. + #[prost(bool, tag = "4")] + pub is_final_settlement: bool, +} +/// Nested message and enum types in `MatchPerpetualDeleveraging`. +pub mod match_perpetual_deleveraging { + /// Fill represents a fill between the liquidated and offsetting subaccount. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Fill { + /// ID of the subaccount that was used to offset the liquidated subaccount's + /// position. + #[prost(message, optional, tag = "1")] + pub offsetting_subaccount_id: ::core::option::Option< + super::super::subaccounts::SubaccountId, + >, + /// The amount filled between the liquidated and offsetting position, in + /// base quantums. + /// TODO(CLOB-571): update to use SerializableInt. + #[prost(uint64, tag = "2")] + pub fill_amount: u64, + } + impl ::prost::Name for Fill { + const NAME: &'static str = "Fill"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MatchPerpetualDeleveraging.Fill".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MatchPerpetualDeleveraging.Fill".into() + } + } +} +impl ::prost::Name for MatchPerpetualDeleveraging { + const NAME: &'static str = "MatchPerpetualDeleveraging"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MatchPerpetualDeleveraging".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MatchPerpetualDeleveraging".into() + } +} +/// MEVMatch represents all necessary data to calculate MEV for a regular match. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MevMatch { + #[prost(message, optional, tag = "1")] + pub taker_order_subaccount_id: ::core::option::Option< + super::subaccounts::SubaccountId, + >, + #[prost(int32, tag = "2")] + pub taker_fee_ppm: i32, + #[prost(message, optional, tag = "3")] + pub maker_order_subaccount_id: ::core::option::Option< + super::subaccounts::SubaccountId, + >, + #[prost(uint64, tag = "4")] + pub maker_order_subticks: u64, + #[prost(bool, tag = "5")] + pub maker_order_is_buy: bool, + #[prost(int32, tag = "6")] + pub maker_fee_ppm: i32, + #[prost(uint32, tag = "7")] + pub clob_pair_id: u32, + #[prost(uint64, tag = "8")] + pub fill_amount: u64, +} +impl ::prost::Name for MevMatch { + const NAME: &'static str = "MEVMatch"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MEVMatch".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MEVMatch".into() + } +} +/// MEVLiquidationMatch represents all necessary data to calculate MEV for a +/// liquidation. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MevLiquidationMatch { + #[prost(message, optional, tag = "1")] + pub liquidated_subaccount_id: ::core::option::Option< + super::subaccounts::SubaccountId, + >, + #[prost(int64, tag = "2")] + pub insurance_fund_delta_quote_quantums: i64, + #[prost(message, optional, tag = "3")] + pub maker_order_subaccount_id: ::core::option::Option< + super::subaccounts::SubaccountId, + >, + #[prost(uint64, tag = "4")] + pub maker_order_subticks: u64, + #[prost(bool, tag = "5")] + pub maker_order_is_buy: bool, + #[prost(int32, tag = "6")] + pub maker_fee_ppm: i32, + #[prost(uint32, tag = "7")] + pub clob_pair_id: u32, + #[prost(uint64, tag = "8")] + pub fill_amount: u64, +} +impl ::prost::Name for MevLiquidationMatch { + const NAME: &'static str = "MEVLiquidationMatch"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MEVLiquidationMatch".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MEVLiquidationMatch".into() + } +} +/// ClobMidPrice contains the mid price of a CLOB pair, represented by it's ID. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClobMidPrice { + #[prost(message, optional, tag = "1")] + pub clob_pair: ::core::option::Option, + #[prost(uint64, tag = "2")] + pub subticks: u64, +} +impl ::prost::Name for ClobMidPrice { + const NAME: &'static str = "ClobMidPrice"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ClobMidPrice".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ClobMidPrice".into() + } +} +/// ValidatorMevMatches contains all matches from the validator's local +/// operations queue. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorMevMatches { + #[prost(message, repeated, tag = "1")] + pub matches: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub liquidation_matches: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for ValidatorMevMatches { + const NAME: &'static str = "ValidatorMevMatches"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ValidatorMevMatches".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ValidatorMevMatches".into() + } +} +/// MevNodeToNodeMetrics is a data structure for encapsulating all MEV node <> +/// node metrics. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MevNodeToNodeMetrics { + #[prost(message, optional, tag = "1")] + pub validator_mev_matches: ::core::option::Option, + #[prost(message, repeated, tag = "2")] + pub clob_mid_prices: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub bp_mev_matches: ::core::option::Option, + #[prost(uint64, tag = "4")] + pub proposal_receive_time: u64, +} +impl ::prost::Name for MevNodeToNodeMetrics { + const NAME: &'static str = "MevNodeToNodeMetrics"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MevNodeToNodeMetrics".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MevNodeToNodeMetrics".into() + } +} +/// OrderRemoval is a request type used for forced removal of stateful orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderRemoval { + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, + #[prost(enumeration = "order_removal::RemovalReason", tag = "2")] + pub removal_reason: i32, +} +/// Nested message and enum types in `OrderRemoval`. +pub mod order_removal { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum RemovalReason { + /// REMOVAL_REASON_UNSPECIFIED represents an unspecified removal reason. This + /// removal reason is used as a catchall and should never appear on an + /// OrderRemoval in the operations queue. + Unspecified = 0, + /// REMOVAL_REASON_UNDERCOLLATERALIZED represents a removal of an order which + /// if filled in isolation with respect to the current state of the + /// subaccount would leave the subaccount undercollateralized. + Undercollateralized = 1, + /// REMOVAL_REASON_INVALID_REDUCE_ONLY represents a removal of a reduce-only + /// order which if filled in isolation with respect to the current state of + /// the subaccount would cause the subaccount's existing position to increase + /// or change sides. + InvalidReduceOnly = 2, + /// REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER represents a removal of + /// a stateful post-only order that was deemed invalid because it crossed + /// maker orders on the book of the proposer. + PostOnlyWouldCrossMakerOrder = 3, + /// REMOVAL_REASON_INVALID_SELF_TRADE represents a removal of a stateful + /// order that was deemed invalid because it constituted a self trade on the + /// proposers orderbook. + InvalidSelfTrade = 4, + /// REMOVAL_REASON_CONDITIONAL_FOK_COULD_NOT_BE_FULLY_FILLED represents a + /// removal of a conditional FOK order that was deemed invalid because it + /// could not be completely filled. Conditional FOK orders should always be + /// fully-filled or removed in the block after they are triggered. + ConditionalFokCouldNotBeFullyFilled = 5, + /// REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK represents a removal + /// of a conditional IOC order. + /// Conditional IOC orders should always have their remaining size removed + /// in the block after they are triggered. + ConditionalIocWouldRestOnBook = 6, + /// REMOVAL_REASON_FULLY_FILLED represents a removal of an order that + /// was fully filled and should therefore be removed from state. + FullyFilled = 7, + /// REMOVAL_REASON_FULLY_FILLED represents a removal of an order that + /// would lead to the subaccount violating isolated subaccount constraints. + ViolatesIsolatedSubaccountConstraints = 8, + } + impl RemovalReason { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + RemovalReason::Unspecified => "REMOVAL_REASON_UNSPECIFIED", + RemovalReason::Undercollateralized => { + "REMOVAL_REASON_UNDERCOLLATERALIZED" + } + RemovalReason::InvalidReduceOnly => "REMOVAL_REASON_INVALID_REDUCE_ONLY", + RemovalReason::PostOnlyWouldCrossMakerOrder => { + "REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" + } + RemovalReason::InvalidSelfTrade => "REMOVAL_REASON_INVALID_SELF_TRADE", + RemovalReason::ConditionalFokCouldNotBeFullyFilled => { + "REMOVAL_REASON_CONDITIONAL_FOK_COULD_NOT_BE_FULLY_FILLED" + } + RemovalReason::ConditionalIocWouldRestOnBook => { + "REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK" + } + RemovalReason::FullyFilled => "REMOVAL_REASON_FULLY_FILLED", + RemovalReason::ViolatesIsolatedSubaccountConstraints => { + "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" + } + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "REMOVAL_REASON_UNSPECIFIED" => Some(Self::Unspecified), + "REMOVAL_REASON_UNDERCOLLATERALIZED" => Some(Self::Undercollateralized), + "REMOVAL_REASON_INVALID_REDUCE_ONLY" => Some(Self::InvalidReduceOnly), + "REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" => { + Some(Self::PostOnlyWouldCrossMakerOrder) + } + "REMOVAL_REASON_INVALID_SELF_TRADE" => Some(Self::InvalidSelfTrade), + "REMOVAL_REASON_CONDITIONAL_FOK_COULD_NOT_BE_FULLY_FILLED" => { + Some(Self::ConditionalFokCouldNotBeFullyFilled) + } + "REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK" => { + Some(Self::ConditionalIocWouldRestOnBook) + } + "REMOVAL_REASON_FULLY_FILLED" => Some(Self::FullyFilled), + "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" => { + Some(Self::ViolatesIsolatedSubaccountConstraints) + } + _ => None, + } + } + } +} +impl ::prost::Name for OrderRemoval { + const NAME: &'static str = "OrderRemoval"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OrderRemoval".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OrderRemoval".into() + } +} +/// MsgCreateClobPair is a message used by x/gov for creating a new clob pair. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateClobPair { + /// The address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// `clob_pair` defines parameters for the new clob pair. + #[prost(message, optional, tag = "2")] + pub clob_pair: ::core::option::Option, +} +impl ::prost::Name for MsgCreateClobPair { + const NAME: &'static str = "MsgCreateClobPair"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgCreateClobPair".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgCreateClobPair".into() + } +} +/// MsgCreateClobPairResponse defines the CreateClobPair response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateClobPairResponse {} +impl ::prost::Name for MsgCreateClobPairResponse { + const NAME: &'static str = "MsgCreateClobPairResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgCreateClobPairResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgCreateClobPairResponse".into() + } +} +/// MsgProposedOperations is a message injected by block proposers to +/// specify the operations that occurred in a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgProposedOperations { + /// The list of operations proposed by the block proposer. + #[prost(message, repeated, tag = "1")] + pub operations_queue: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgProposedOperations { + const NAME: &'static str = "MsgProposedOperations"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgProposedOperations".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgProposedOperations".into() + } +} +/// MsgProposedOperationsResponse is the response type of the message injected +/// by block proposers to specify the operations that occurred in a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgProposedOperationsResponse {} +impl ::prost::Name for MsgProposedOperationsResponse { + const NAME: &'static str = "MsgProposedOperationsResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgProposedOperationsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgProposedOperationsResponse".into() + } +} +/// MsgPlaceOrder is a request type used for placing orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPlaceOrder { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, +} +impl ::prost::Name for MsgPlaceOrder { + const NAME: &'static str = "MsgPlaceOrder"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgPlaceOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgPlaceOrder".into() + } +} +/// MsgPlaceOrderResponse is a response type used for placing orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPlaceOrderResponse {} +impl ::prost::Name for MsgPlaceOrderResponse { + const NAME: &'static str = "MsgPlaceOrderResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgPlaceOrderResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgPlaceOrderResponse".into() + } +} +/// MsgCancelOrder is a request type used for canceling orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCancelOrder { + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, + /// Information about when the order cancellation expires. + #[prost(oneof = "msg_cancel_order::GoodTilOneof", tags = "2, 3")] + pub good_til_oneof: ::core::option::Option, +} +/// Nested message and enum types in `MsgCancelOrder`. +pub mod msg_cancel_order { + /// Information about when the order cancellation expires. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum GoodTilOneof { + /// The last block this order cancellation can be executed at. + /// Used only for Short-Term orders and must be zero for stateful orders. + #[prost(uint32, tag = "2")] + GoodTilBlock(u32), + /// good_til_block_time represents the unix timestamp (in seconds) at which a + /// stateful order cancellation will be considered expired. The + /// good_til_block_time is always evaluated against the previous block's + /// `BlockTime` instead of the block in which the order is committed. + /// This value must be zero for Short-Term orders. + #[prost(fixed32, tag = "3")] + GoodTilBlockTime(u32), + } +} +impl ::prost::Name for MsgCancelOrder { + const NAME: &'static str = "MsgCancelOrder"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgCancelOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgCancelOrder".into() + } +} +/// MsgCancelOrderResponse is a response type used for canceling orders. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCancelOrderResponse {} +impl ::prost::Name for MsgCancelOrderResponse { + const NAME: &'static str = "MsgCancelOrderResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgCancelOrderResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgCancelOrderResponse".into() + } +} +/// MsgBatchCancel is a request type used for batch canceling orders. +/// This msg is not atomic. Cancels will be performed optimistically even +/// if some cancels are invalid or fail. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgBatchCancel { + /// The subaccount this batch cancel will be applied for. + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// The batch of short term orders that will be cancelled. + #[prost(message, repeated, tag = "2")] + pub short_term_cancels: ::prost::alloc::vec::Vec, + /// The last block the short term order cancellations can be executed at. + #[prost(uint32, tag = "3")] + pub good_til_block: u32, +} +impl ::prost::Name for MsgBatchCancel { + const NAME: &'static str = "MsgBatchCancel"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgBatchCancel".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgBatchCancel".into() + } +} +/// OrderBatch represents a batch of orders all belonging to a single clob pair +/// id. Along with a subaccount id and an order flag, is used to represent a +/// batch of orders that share the same subaccount, order flag, and clob pair id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderBatch { + /// The Clob Pair ID all orders in this order batch belong to. + #[prost(uint32, tag = "1")] + pub clob_pair_id: u32, + /// List of client ids in this order batch. + /// Note that this is serialized as a uint32 instead of a fixed32 to + /// avoid issues when decoding repeated packed fixed32. + #[prost(uint32, repeated, tag = "2")] + pub client_ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for OrderBatch { + const NAME: &'static str = "OrderBatch"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OrderBatch".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OrderBatch".into() + } +} +/// MsgBatchCancelResponse is a response type used for batch canceling orders. +/// It indicates which cancel orders have succeeded or failed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgBatchCancelResponse { + /// A batch of short term cancel orders that have succeeded. + #[prost(message, repeated, tag = "1")] + pub short_term_succeeded: ::prost::alloc::vec::Vec, + /// A batch of short term cancel orders that have failed. + #[prost(message, repeated, tag = "2")] + pub short_term_failed: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgBatchCancelResponse { + const NAME: &'static str = "MsgBatchCancelResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgBatchCancelResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgBatchCancelResponse".into() + } +} +/// MsgUpdateClobPair is a request type used for updating a ClobPair in state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateClobPair { + /// Authority is the address that may send this message. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// `clob_pair` is the ClobPair to write to state. + #[prost(message, optional, tag = "2")] + pub clob_pair: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateClobPair { + const NAME: &'static str = "MsgUpdateClobPair"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateClobPair".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateClobPair".into() + } +} +/// MsgUpdateClobPairResponse is a response type used for setting a ClobPair's +/// status. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateClobPairResponse {} +impl ::prost::Name for MsgUpdateClobPairResponse { + const NAME: &'static str = "MsgUpdateClobPairResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateClobPairResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateClobPairResponse".into() + } +} +/// OperationRaw represents an operation in the proposed operations. +/// Note that the `order_placement` operation is a signed message. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OperationRaw { + /// operationRaw represents an operation that occurred, which can be a match, + /// a signed order placement, or an order removal. + #[prost(oneof = "operation_raw::Operation", tags = "1, 2, 3")] + pub operation: ::core::option::Option, +} +/// Nested message and enum types in `OperationRaw`. +pub mod operation_raw { + /// operationRaw represents an operation that occurred, which can be a match, + /// a signed order placement, or an order removal. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Operation { + #[prost(message, tag = "1")] + Match(super::ClobMatch), + #[prost(bytes, tag = "2")] + ShortTermOrderPlacement(::prost::alloc::vec::Vec), + #[prost(message, tag = "3")] + OrderRemoval(super::OrderRemoval), + } +} +impl ::prost::Name for OperationRaw { + const NAME: &'static str = "OperationRaw"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.OperationRaw".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.OperationRaw".into() + } +} +/// MsgUpdateEquityTierLimitConfiguration is the Msg/EquityTierLimitConfiguration +/// request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateEquityTierLimitConfiguration { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the equity tier limit configuration to update to. All fields must + /// be set. + #[prost(message, optional, tag = "2")] + pub equity_tier_limit_config: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateEquityTierLimitConfiguration { + const NAME: &'static str = "MsgUpdateEquityTierLimitConfiguration"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateEquityTierLimitConfiguration".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateEquityTierLimitConfiguration".into() + } +} +/// MsgUpdateEquityTierLimitConfiguration is the Msg/EquityTierLimitConfiguration +/// response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateEquityTierLimitConfigurationResponse {} +impl ::prost::Name for MsgUpdateEquityTierLimitConfigurationResponse { + const NAME: &'static str = "MsgUpdateEquityTierLimitConfigurationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateEquityTierLimitConfigurationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateEquityTierLimitConfigurationResponse".into() + } +} +/// MsgUpdateBlockRateLimitConfiguration is the Msg/BlockRateLimitConfiguration +/// request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateBlockRateLimitConfiguration { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the block rate limit configuration to update to. All fields must be + /// set. + #[prost(message, optional, tag = "3")] + pub block_rate_limit_config: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateBlockRateLimitConfiguration { + const NAME: &'static str = "MsgUpdateBlockRateLimitConfiguration"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateBlockRateLimitConfiguration".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateBlockRateLimitConfiguration".into() + } +} +/// MsgUpdateBlockRateLimitConfiguration is a response type for updating the +/// liquidations config. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateBlockRateLimitConfigurationResponse {} +impl ::prost::Name for MsgUpdateBlockRateLimitConfigurationResponse { + const NAME: &'static str = "MsgUpdateBlockRateLimitConfigurationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateBlockRateLimitConfigurationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateBlockRateLimitConfigurationResponse".into() + } +} +/// MsgUpdateLiquidationsConfig is a request type for updating the liquidations +/// config. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateLiquidationsConfig { + /// Authority is the address that may send this message. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the liquidations configuration to update to. All fields must + /// be set. + #[prost(message, optional, tag = "2")] + pub liquidations_config: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateLiquidationsConfig { + const NAME: &'static str = "MsgUpdateLiquidationsConfig"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateLiquidationsConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateLiquidationsConfig".into() + } +} +/// MsgUpdateLiquidationsConfig is the Msg/LiquidationsConfig response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateLiquidationsConfigResponse {} +impl ::prost::Name for MsgUpdateLiquidationsConfigResponse { + const NAME: &'static str = "MsgUpdateLiquidationsConfigResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MsgUpdateLiquidationsConfigResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MsgUpdateLiquidationsConfigResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// ProposedOperations is a temporary message used by block proposers + /// for matching orders as part of the ABCI++ workaround. + pub async fn proposed_operations( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/ProposedOperations", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "ProposedOperations")); + self.inner.unary(req, path, codec).await + } + /// PlaceOrder allows accounts to place orders on the orderbook. + pub async fn place_order( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/PlaceOrder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "PlaceOrder")); + self.inner.unary(req, path, codec).await + } + /// CancelOrder allows accounts to cancel existing orders on the orderbook. + pub async fn cancel_order( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/CancelOrder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "CancelOrder")); + self.inner.unary(req, path, codec).await + } + /// BatchCancel allows accounts to cancel a batch of orders on the orderbook. + pub async fn batch_cancel( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/BatchCancel", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "BatchCancel")); + self.inner.unary(req, path, codec).await + } + /// CreateClobPair creates a new clob pair. + pub async fn create_clob_pair( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/CreateClobPair", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "CreateClobPair")); + self.inner.unary(req, path, codec).await + } + /// UpdateClobPair sets the status of a clob pair. Should return an error + /// if the authority is not in the clob keeper's set of authorities, + /// if the ClobPair id is not found in state, or if the update includes + /// an unsupported status transition. + pub async fn update_clob_pair( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/UpdateClobPair", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Msg", "UpdateClobPair")); + self.inner.unary(req, path, codec).await + } + /// UpdateEquityTierLimitConfiguration updates the equity tier limit + /// configuration in state. + pub async fn update_equity_tier_limit_configuration( + &mut self, + request: impl tonic::IntoRequest< + super::MsgUpdateEquityTierLimitConfiguration, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/UpdateEquityTierLimitConfiguration", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Msg", + "UpdateEquityTierLimitConfiguration", + ), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateBlockRateLimitConfiguration updates the block rate limit + /// configuration in state. + pub async fn update_block_rate_limit_configuration( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/UpdateBlockRateLimitConfiguration", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Msg", + "UpdateBlockRateLimitConfiguration", + ), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateLiquidationsConfig updates the liquidations configuration in state. + pub async fn update_liquidations_config( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Msg/UpdateLiquidationsConfig", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.clob.Msg", "UpdateLiquidationsConfig"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Operation represents an operation in the proposed operations. Operation is +/// used internally within the memclob only. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Operation { + /// operation represents the operation that occurred, which can be a match, + /// short term order placement, short term order cancellation, or the placement + /// of a pre-existing stateful order. + #[prost(oneof = "operation::Operation", tags = "1, 2, 3, 4")] + pub operation: ::core::option::Option, +} +/// Nested message and enum types in `Operation`. +pub mod operation { + /// operation represents the operation that occurred, which can be a match, + /// short term order placement, short term order cancellation, or the placement + /// of a pre-existing stateful order. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Operation { + #[prost(message, tag = "1")] + Match(super::ClobMatch), + #[prost(message, tag = "2")] + ShortTermOrderPlacement(super::MsgPlaceOrder), + #[prost(message, tag = "3")] + ShortTermOrderCancellation(super::MsgCancelOrder), + #[prost(message, tag = "4")] + PreexistingStatefulOrder(super::OrderId), + } +} +impl ::prost::Name for Operation { + const NAME: &'static str = "Operation"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.Operation".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.Operation".into() + } +} +/// InternalOperation represents an internal operation in the operations to +/// propose. InternalOperation is used internally within the memclob only. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InternalOperation { + /// operation represents the operation that occurred, which can be a match, + /// Short-Term order placement, or the placement of a pre-existing stateful + /// order. + #[prost(oneof = "internal_operation::Operation", tags = "1, 2, 3, 4")] + pub operation: ::core::option::Option, +} +/// Nested message and enum types in `InternalOperation`. +pub mod internal_operation { + /// operation represents the operation that occurred, which can be a match, + /// Short-Term order placement, or the placement of a pre-existing stateful + /// order. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Operation { + #[prost(message, tag = "1")] + Match(super::ClobMatch), + #[prost(message, tag = "2")] + ShortTermOrderPlacement(super::MsgPlaceOrder), + #[prost(message, tag = "3")] + PreexistingStatefulOrder(super::OrderId), + #[prost(message, tag = "4")] + OrderRemoval(super::OrderRemoval), + } +} +impl ::prost::Name for InternalOperation { + const NAME: &'static str = "InternalOperation"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.InternalOperation".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.InternalOperation".into() + } +} +/// ProcessProposerMatchesEvents is used for communicating which events occurred +/// in the last block that require updating the state of the memclob in the +/// Commit blocker. It contains information about the following state updates: +/// - Long term order IDs that were placed in the last block. +/// - Stateful order IDs that were expired in the last block. +/// - Order IDs that were filled in the last block. +/// - Stateful cancellations order IDs that were placed in the last block. +/// - Stateful order IDs forcefully removed in the last block. +/// - Conditional order IDs triggered in the last block. +/// - Conditional order IDs placed, but not triggered in the last block. +/// - The height of the block in which the events occurred. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProcessProposerMatchesEvents { + #[prost(message, repeated, tag = "1")] + pub placed_long_term_order_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub expired_stateful_order_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub order_ids_filled_in_last_block: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub placed_stateful_cancellation_order_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub removed_stateful_order_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "6")] + pub conditional_order_ids_triggered_in_last_block: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "7")] + pub placed_conditional_order_ids: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "8")] + pub block_height: u32, +} +impl ::prost::Name for ProcessProposerMatchesEvents { + const NAME: &'static str = "ProcessProposerMatchesEvents"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ProcessProposerMatchesEvents".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ProcessProposerMatchesEvents".into() + } +} +/// QueryGetClobPairRequest is request type for the ClobPair method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGetClobPairRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryGetClobPairRequest { + const NAME: &'static str = "QueryGetClobPairRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryGetClobPairRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryGetClobPairRequest".into() + } +} +/// QueryClobPairResponse is response type for the ClobPair method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryClobPairResponse { + #[prost(message, optional, tag = "1")] + pub clob_pair: ::core::option::Option, +} +impl ::prost::Name for QueryClobPairResponse { + const NAME: &'static str = "QueryClobPairResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryClobPairResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryClobPairResponse".into() + } +} +/// QueryAllClobPairRequest is request type for the ClobPairAll method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllClobPairRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllClobPairRequest { + const NAME: &'static str = "QueryAllClobPairRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryAllClobPairRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryAllClobPairRequest".into() + } +} +/// QueryClobPairAllResponse is response type for the ClobPairAll method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryClobPairAllResponse { + #[prost(message, repeated, tag = "1")] + pub clob_pair: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryClobPairAllResponse { + const NAME: &'static str = "QueryClobPairAllResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryClobPairAllResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryClobPairAllResponse".into() + } +} +/// MevNodeToNodeCalculationRequest is a request message used to run the +/// MEV node <> node calculation. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MevNodeToNodeCalculationRequest { + /// Represents the matches on the "block proposer". Note that this field + /// does not need to be the actual block proposer's matches for a block, since + /// the MEV calculation logic is run with this nodes matches as the "block + /// proposer" matches. + #[prost(message, optional, tag = "1")] + pub block_proposer_matches: ::core::option::Option, + /// Represents the matches and mid-prices on the validator. + #[prost(message, optional, tag = "2")] + pub validator_mev_metrics: ::core::option::Option, +} +impl ::prost::Name for MevNodeToNodeCalculationRequest { + const NAME: &'static str = "MevNodeToNodeCalculationRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MevNodeToNodeCalculationRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MevNodeToNodeCalculationRequest".into() + } +} +/// MevNodeToNodeCalculationResponse is a response message that contains the +/// MEV node <> node calculation result. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MevNodeToNodeCalculationResponse { + #[prost(message, repeated, tag = "1")] + pub results: ::prost::alloc::vec::Vec< + mev_node_to_node_calculation_response::MevAndVolumePerClob, + >, +} +/// Nested message and enum types in `MevNodeToNodeCalculationResponse`. +pub mod mev_node_to_node_calculation_response { + /// MevAndVolumePerClob contains information about the MEV and volume per CLOB. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MevAndVolumePerClob { + #[prost(uint32, tag = "1")] + pub clob_pair_id: u32, + #[prost(float, tag = "2")] + pub mev: f32, + #[prost(uint64, tag = "3")] + pub volume: u64, + } + impl ::prost::Name for MevAndVolumePerClob { + const NAME: &'static str = "MevAndVolumePerClob"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MevNodeToNodeCalculationResponse.MevAndVolumePerClob" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MevNodeToNodeCalculationResponse.MevAndVolumePerClob" + .into() + } + } +} +impl ::prost::Name for MevNodeToNodeCalculationResponse { + const NAME: &'static str = "MevNodeToNodeCalculationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.MevNodeToNodeCalculationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.MevNodeToNodeCalculationResponse".into() + } +} +/// QueryEquityTierLimitConfigurationRequest is a request message for +/// EquityTierLimitConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEquityTierLimitConfigurationRequest {} +impl ::prost::Name for QueryEquityTierLimitConfigurationRequest { + const NAME: &'static str = "QueryEquityTierLimitConfigurationRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryEquityTierLimitConfigurationRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryEquityTierLimitConfigurationRequest".into() + } +} +/// QueryEquityTierLimitConfigurationResponse is a response message that contains +/// the EquityTierLimitConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEquityTierLimitConfigurationResponse { + #[prost(message, optional, tag = "1")] + pub equity_tier_limit_config: ::core::option::Option, +} +impl ::prost::Name for QueryEquityTierLimitConfigurationResponse { + const NAME: &'static str = "QueryEquityTierLimitConfigurationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryEquityTierLimitConfigurationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryEquityTierLimitConfigurationResponse".into() + } +} +/// QueryBlockRateLimitConfigurationRequest is a request message for +/// BlockRateLimitConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockRateLimitConfigurationRequest {} +impl ::prost::Name for QueryBlockRateLimitConfigurationRequest { + const NAME: &'static str = "QueryBlockRateLimitConfigurationRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryBlockRateLimitConfigurationRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryBlockRateLimitConfigurationRequest".into() + } +} +/// QueryBlockRateLimitConfigurationResponse is a response message that contains +/// the BlockRateLimitConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockRateLimitConfigurationResponse { + #[prost(message, optional, tag = "1")] + pub block_rate_limit_config: ::core::option::Option, +} +impl ::prost::Name for QueryBlockRateLimitConfigurationResponse { + const NAME: &'static str = "QueryBlockRateLimitConfigurationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryBlockRateLimitConfigurationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryBlockRateLimitConfigurationResponse".into() + } +} +/// QueryStatefulOrderRequest is a request message for StatefulOrder. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryStatefulOrderRequest { + /// Order id to query. + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, +} +impl ::prost::Name for QueryStatefulOrderRequest { + const NAME: &'static str = "QueryStatefulOrderRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryStatefulOrderRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryStatefulOrderRequest".into() + } +} +/// QueryStatefulOrderResponse is a response message that contains the stateful +/// order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryStatefulOrderResponse { + /// Stateful order placement. + #[prost(message, optional, tag = "1")] + pub order_placement: ::core::option::Option, + /// Fill amounts. + #[prost(uint64, tag = "2")] + pub fill_amount: u64, + /// Triggered status. + #[prost(bool, tag = "3")] + pub triggered: bool, +} +impl ::prost::Name for QueryStatefulOrderResponse { + const NAME: &'static str = "QueryStatefulOrderResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryStatefulOrderResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryStatefulOrderResponse".into() + } +} +/// QueryLiquidationsConfigurationRequest is a request message for +/// LiquidationsConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryLiquidationsConfigurationRequest {} +impl ::prost::Name for QueryLiquidationsConfigurationRequest { + const NAME: &'static str = "QueryLiquidationsConfigurationRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryLiquidationsConfigurationRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryLiquidationsConfigurationRequest".into() + } +} +/// QueryLiquidationsConfigurationResponse is a response message that contains +/// the LiquidationsConfiguration. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryLiquidationsConfigurationResponse { + #[prost(message, optional, tag = "1")] + pub liquidations_config: ::core::option::Option, +} +impl ::prost::Name for QueryLiquidationsConfigurationResponse { + const NAME: &'static str = "QueryLiquidationsConfigurationResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.QueryLiquidationsConfigurationResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.QueryLiquidationsConfigurationResponse".into() + } +} +/// StreamOrderbookUpdatesRequest is a request message for the +/// StreamOrderbookUpdates method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamOrderbookUpdatesRequest { + /// Clob pair ids to stream orderbook updates for. + #[prost(uint32, repeated, tag = "1")] + pub clob_pair_id: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for StreamOrderbookUpdatesRequest { + const NAME: &'static str = "StreamOrderbookUpdatesRequest"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamOrderbookUpdatesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamOrderbookUpdatesRequest".into() + } +} +/// StreamOrderbookUpdatesResponse is a response message for the +/// StreamOrderbookUpdates method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamOrderbookUpdatesResponse { + /// Orderbook updates for the clob pair. + #[prost(message, repeated, tag = "1")] + pub updates: ::prost::alloc::vec::Vec, + /// ---Additional fields used to debug issues--- + /// Block height of the updates. + #[prost(uint32, tag = "2")] + pub block_height: u32, + /// Exec mode of the updates. + #[prost(uint32, tag = "3")] + pub exec_mode: u32, +} +impl ::prost::Name for StreamOrderbookUpdatesResponse { + const NAME: &'static str = "StreamOrderbookUpdatesResponse"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamOrderbookUpdatesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamOrderbookUpdatesResponse".into() + } +} +/// StreamUpdate is an update that will be pushed through the +/// GRPC stream. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamUpdate { + /// Contains one of an StreamOrderbookUpdate, + /// StreamOrderbookFill. + #[prost(oneof = "stream_update::UpdateMessage", tags = "1, 2")] + pub update_message: ::core::option::Option, +} +/// Nested message and enum types in `StreamUpdate`. +pub mod stream_update { + /// Contains one of an StreamOrderbookUpdate, + /// StreamOrderbookFill. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum UpdateMessage { + #[prost(message, tag = "1")] + OrderbookUpdate(super::StreamOrderbookUpdate), + #[prost(message, tag = "2")] + OrderFill(super::StreamOrderbookFill), + } +} +impl ::prost::Name for StreamUpdate { + const NAME: &'static str = "StreamUpdate"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamUpdate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamUpdate".into() + } +} +/// StreamOrderbookUpdate provides information on an orderbook update. Used in +/// the full node GRPC stream. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamOrderbookUpdate { + /// Orderbook updates for the clob pair. Can contain order place, removals, + /// or updates. + #[prost(message, repeated, tag = "1")] + pub updates: ::prost::alloc::vec::Vec< + super::indexer::off_chain_updates::OffChainUpdateV1, + >, + /// Snapshot indicates if the response is from a snapshot of the orderbook. + /// This is true for the initial response and false for all subsequent updates. + /// Note that if the snapshot is true, then all previous entries should be + /// discarded and the orderbook should be resynced. + #[prost(bool, tag = "2")] + pub snapshot: bool, +} +impl ::prost::Name for StreamOrderbookUpdate { + const NAME: &'static str = "StreamOrderbookUpdate"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamOrderbookUpdate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamOrderbookUpdate".into() + } +} +/// StreamOrderbookFill provides information on an orderbook fill. Used in +/// the full node GRPC stream. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamOrderbookFill { + /// Clob match. Provides information on which orders were matched + /// and the type of order. Fill amounts here are relative. + #[prost(message, optional, tag = "1")] + pub clob_match: ::core::option::Option, + /// All orders involved in the specified clob match. Used to look up + /// price of a match through a given maker order id. + #[prost(message, repeated, tag = "2")] + pub orders: ::prost::alloc::vec::Vec, + /// Resulting fill amounts for each order in the orders array. + #[prost(uint64, repeated, packed = "false", tag = "3")] + pub fill_amounts: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for StreamOrderbookFill { + const NAME: &'static str = "StreamOrderbookFill"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamOrderbookFill".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamOrderbookFill".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a ClobPair by id. + pub async fn clob_pair( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/ClobPair", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Query", "ClobPair")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of ClobPair items. + pub async fn clob_pair_all( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/ClobPairAll", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Query", "ClobPairAll")); + self.inner.unary(req, path, codec).await + } + /// Runs the MEV node <> node calculation with the provided parameters. + pub async fn mev_node_to_node_calculation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/MevNodeToNodeCalculation", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Query", + "MevNodeToNodeCalculation", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries EquityTierLimitConfiguration. + pub async fn equity_tier_limit_configuration( + &mut self, + request: impl tonic::IntoRequest< + super::QueryEquityTierLimitConfigurationRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/EquityTierLimitConfiguration", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Query", + "EquityTierLimitConfiguration", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries BlockRateLimitConfiguration. + pub async fn block_rate_limit_configuration( + &mut self, + request: impl tonic::IntoRequest< + super::QueryBlockRateLimitConfigurationRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/BlockRateLimitConfiguration", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Query", + "BlockRateLimitConfiguration", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries LiquidationsConfiguration. + pub async fn liquidations_configuration( + &mut self, + request: impl tonic::IntoRequest< + super::QueryLiquidationsConfigurationRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/LiquidationsConfiguration", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.clob.Query", + "LiquidationsConfiguration", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the stateful order for a given order id. + pub async fn stateful_order( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/StatefulOrder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.clob.Query", "StatefulOrder")); + self.inner.unary(req, path, codec).await + } + /// Streams orderbook updates. Updates contain orderbook data + /// such as order placements, updates, and fills. + pub async fn stream_orderbook_updates( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response< + tonic::codec::Streaming, + >, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.clob.Query/StreamOrderbookUpdates", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.clob.Query", "StreamOrderbookUpdates"), + ); + self.inner.server_streaming(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs b/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs new file mode 100644 index 0000000000..ae7eb45729 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs @@ -0,0 +1,152 @@ +// This file is @generated by prost-build. +/// AddBridgeEventsRequest is a request message that contains a list of new +/// bridge events. The events should be contiguous and sorted by (unique) id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddBridgeEventsRequest { + #[prost(message, repeated, tag = "1")] + pub bridge_events: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AddBridgeEventsRequest { + const NAME: &'static str = "AddBridgeEventsRequest"; + const PACKAGE: &'static str = "dydxprotocol.daemons.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.bridge.AddBridgeEventsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.bridge.AddBridgeEventsRequest".into() + } +} +/// AddBridgeEventsResponse is a response message for BridgeEventRequest. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddBridgeEventsResponse {} +impl ::prost::Name for AddBridgeEventsResponse { + const NAME: &'static str = "AddBridgeEventsResponse"; + const PACKAGE: &'static str = "dydxprotocol.daemons.bridge"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.bridge.AddBridgeEventsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.bridge.AddBridgeEventsResponse".into() + } +} +/// Generated client implementations. +pub mod bridge_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// BridgeService defines the gRPC service used by bridge daemon. + #[derive(Debug, Clone)] + pub struct BridgeServiceClient { + inner: tonic::client::Grpc, + } + impl BridgeServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl BridgeServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> BridgeServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + BridgeServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Sends a list of newly recognized bridge events. + pub async fn add_bridge_events( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.daemons.bridge.BridgeService/AddBridgeEvents", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.daemons.bridge.BridgeService", + "AddBridgeEvents", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs b/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs new file mode 100644 index 0000000000..b87a3eed41 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs @@ -0,0 +1,171 @@ +// This file is @generated by prost-build. +/// LiquidateSubaccountsRequest is a request message that contains a list of +/// subaccount ids that potentially need to be liquidated. The list of subaccount +/// ids should not contain duplicates. The application should re-verify these +/// subaccount ids against current state before liquidating their positions. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidateSubaccountsRequest { + /// The block height at which the liquidation daemon is processing. + #[prost(uint32, tag = "1")] + pub block_height: u32, + /// The list of liquidatable subaccount ids. + #[prost(message, repeated, tag = "2")] + pub liquidatable_subaccount_ids: ::prost::alloc::vec::Vec< + super::super::subaccounts::SubaccountId, + >, + /// The list of subaccount ids with negative total net collateral. + #[prost(message, repeated, tag = "3")] + pub negative_tnc_subaccount_ids: ::prost::alloc::vec::Vec< + super::super::subaccounts::SubaccountId, + >, + /// A map of perpetual id to subaccount open position info. + #[prost(message, repeated, tag = "4")] + pub subaccount_open_position_info: ::prost::alloc::vec::Vec< + super::super::clob::SubaccountOpenPositionInfo, + >, +} +impl ::prost::Name for LiquidateSubaccountsRequest { + const NAME: &'static str = "LiquidateSubaccountsRequest"; + const PACKAGE: &'static str = "dydxprotocol.daemons.liquidation"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.liquidation.LiquidateSubaccountsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.liquidation.LiquidateSubaccountsRequest".into() + } +} +/// LiquidateSubaccountsResponse is a response message for +/// LiquidateSubaccountsRequest. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidateSubaccountsResponse {} +impl ::prost::Name for LiquidateSubaccountsResponse { + const NAME: &'static str = "LiquidateSubaccountsResponse"; + const PACKAGE: &'static str = "dydxprotocol.daemons.liquidation"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.liquidation.LiquidateSubaccountsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.liquidation.LiquidateSubaccountsResponse".into() + } +} +/// Generated client implementations. +pub mod liquidation_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// LiquidationService defines the gRPC service used by liquidation daemon. + #[derive(Debug, Clone)] + pub struct LiquidationServiceClient { + inner: tonic::client::Grpc, + } + impl LiquidationServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl LiquidationServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> LiquidationServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + LiquidationServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Sends a list of subaccount ids that are potentially liquidatable. + pub async fn liquidate_subaccounts( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.daemons.liquidation.LiquidationService/LiquidateSubaccounts", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.daemons.liquidation.LiquidationService", + "LiquidateSubaccounts", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs b/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs new file mode 100644 index 0000000000..bb273d7232 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs @@ -0,0 +1,191 @@ +// This file is @generated by prost-build. +/// UpdateMarketPriceRequest is a request message updating market prices. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateMarketPricesRequest { + #[prost(message, repeated, tag = "1")] + pub market_price_updates: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for UpdateMarketPricesRequest { + const NAME: &'static str = "UpdateMarketPricesRequest"; + const PACKAGE: &'static str = "dydxprotocol.daemons.pricefeed"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.pricefeed.UpdateMarketPricesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.pricefeed.UpdateMarketPricesRequest".into() + } +} +/// UpdateMarketPricesResponse is a response message for updating market prices. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateMarketPricesResponse {} +impl ::prost::Name for UpdateMarketPricesResponse { + const NAME: &'static str = "UpdateMarketPricesResponse"; + const PACKAGE: &'static str = "dydxprotocol.daemons.pricefeed"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.pricefeed.UpdateMarketPricesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.pricefeed.UpdateMarketPricesResponse".into() + } +} +/// ExchangePrice represents a specific exchange's market price +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExchangePrice { + #[prost(string, tag = "1")] + pub exchange_id: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub price: u64, + #[prost(message, optional, tag = "3")] + pub last_update_time: ::core::option::Option<::prost_types::Timestamp>, +} +impl ::prost::Name for ExchangePrice { + const NAME: &'static str = "ExchangePrice"; + const PACKAGE: &'static str = "dydxprotocol.daemons.pricefeed"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.pricefeed.ExchangePrice".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.pricefeed.ExchangePrice".into() + } +} +/// MarketPriceUpdate represents an update to a single market +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketPriceUpdate { + #[prost(uint32, tag = "1")] + pub market_id: u32, + #[prost(message, repeated, tag = "2")] + pub exchange_prices: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MarketPriceUpdate { + const NAME: &'static str = "MarketPriceUpdate"; + const PACKAGE: &'static str = "dydxprotocol.daemons.pricefeed"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.daemons.pricefeed.MarketPriceUpdate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.daemons.pricefeed.MarketPriceUpdate".into() + } +} +/// Generated client implementations. +pub mod price_feed_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// PriceFeedService provides methods related to market prices. + #[derive(Debug, Clone)] + pub struct PriceFeedServiceClient { + inner: tonic::client::Grpc, + } + impl PriceFeedServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl PriceFeedServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> PriceFeedServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + PriceFeedServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Updates market prices. + pub async fn update_market_prices( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.daemons.pricefeed.PriceFeedService/UpdateMarketPrices", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.daemons.pricefeed.PriceFeedService", + "UpdateMarketPrices", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.delaymsg.rs b/v4-proto-rs/src/dydxprotocol.delaymsg.rs new file mode 100644 index 0000000000..b4e043a63f --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.delaymsg.rs @@ -0,0 +1,498 @@ +// This file is @generated by prost-build. +/// BlockMessageIds stores the id of each message that should be processed at a +/// given block height. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockMessageIds { + /// ids stores a list of DelayedMessage ids that should be processed at a given + /// block height. + #[prost(uint32, repeated, tag = "1")] + pub ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for BlockMessageIds { + const NAME: &'static str = "BlockMessageIds"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.BlockMessageIds".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.BlockMessageIds".into() + } +} +/// DelayedMessage is a message that is delayed until a certain block height. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DelayedMessage { + /// The ID of the delayed message. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The message to be executed. + #[prost(message, optional, tag = "2")] + pub msg: ::core::option::Option<::prost_types::Any>, + /// The block height at which the message should be executed. + #[prost(uint32, tag = "3")] + pub block_height: u32, +} +impl ::prost::Name for DelayedMessage { + const NAME: &'static str = "DelayedMessage"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.DelayedMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.DelayedMessage".into() + } +} +/// GenesisState defines the delaymsg module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// delayed_messages is a list of delayed messages. + #[prost(message, repeated, tag = "1")] + pub delayed_messages: ::prost::alloc::vec::Vec, + /// next_delayed_message_id is the id to be assigned to next delayed message. + #[prost(uint32, tag = "2")] + pub next_delayed_message_id: u32, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.GenesisState".into() + } +} +/// QueryNextDelayedMessageIdRequest is the request type for the +/// NextDelayedMessageId RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryNextDelayedMessageIdRequest {} +impl ::prost::Name for QueryNextDelayedMessageIdRequest { + const NAME: &'static str = "QueryNextDelayedMessageIdRequest"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryNextDelayedMessageIdRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryNextDelayedMessageIdRequest".into() + } +} +/// QueryNextDelayedMessageIdResponse is the response type for the +/// NextDelayedMessageId RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryNextDelayedMessageIdResponse { + #[prost(uint32, tag = "1")] + pub next_delayed_message_id: u32, +} +impl ::prost::Name for QueryNextDelayedMessageIdResponse { + const NAME: &'static str = "QueryNextDelayedMessageIdResponse"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryNextDelayedMessageIdResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryNextDelayedMessageIdResponse".into() + } +} +/// QueryMessageRequest is the request type for the Message RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMessageRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryMessageRequest { + const NAME: &'static str = "QueryMessageRequest"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryMessageRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryMessageRequest".into() + } +} +/// QueryGetMessageResponse is the response type for the Message RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMessageResponse { + #[prost(message, optional, tag = "1")] + pub message: ::core::option::Option, +} +impl ::prost::Name for QueryMessageResponse { + const NAME: &'static str = "QueryMessageResponse"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryMessageResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryMessageResponse".into() + } +} +/// QueryBlockMessageIdsRequest is the request type for the BlockMessageIds +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockMessageIdsRequest { + #[prost(uint32, tag = "1")] + pub block_height: u32, +} +impl ::prost::Name for QueryBlockMessageIdsRequest { + const NAME: &'static str = "QueryBlockMessageIdsRequest"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryBlockMessageIdsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryBlockMessageIdsRequest".into() + } +} +/// QueryGetBlockMessageIdsResponse is the response type for the BlockMessageIds +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryBlockMessageIdsResponse { + #[prost(uint32, repeated, tag = "1")] + pub message_ids: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryBlockMessageIdsResponse { + const NAME: &'static str = "QueryBlockMessageIdsResponse"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.QueryBlockMessageIdsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.QueryBlockMessageIdsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the next DelayedMessage's id. + pub async fn next_delayed_message_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.delaymsg.Query/NextDelayedMessageId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.delaymsg.Query", + "NextDelayedMessageId", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the DelayedMessage by id. + pub async fn message( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.delaymsg.Query/Message", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.delaymsg.Query", "Message")); + self.inner.unary(req, path, codec).await + } + /// Queries the DelayedMessages at a given block height. + pub async fn block_message_ids( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.delaymsg.Query/BlockMessageIds", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.delaymsg.Query", "BlockMessageIds"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgDelayMessage is a request type for the DelayMessage method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDelayMessage { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The message to be delayed. + #[prost(message, optional, tag = "2")] + pub msg: ::core::option::Option<::prost_types::Any>, + /// The number of blocks to delay the message for. + #[prost(uint32, tag = "3")] + pub delay_blocks: u32, +} +impl ::prost::Name for MsgDelayMessage { + const NAME: &'static str = "MsgDelayMessage"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.MsgDelayMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.MsgDelayMessage".into() + } +} +/// MsgDelayMessageResponse is a response type for the DelayMessage method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDelayMessageResponse { + /// The id of the created delayed message. + #[prost(uint64, tag = "1")] + pub id: u64, +} +impl ::prost::Name for MsgDelayMessageResponse { + const NAME: &'static str = "MsgDelayMessageResponse"; + const PACKAGE: &'static str = "dydxprotocol.delaymsg"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.delaymsg.MsgDelayMessageResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.delaymsg.MsgDelayMessageResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// DelayMessage delays the execution of a message for a given number of + /// blocks. + pub async fn delay_message( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.delaymsg.Msg/DelayMessage", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.delaymsg.Msg", "DelayMessage")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.epochs.rs b/v4-proto-rs/src/dydxprotocol.epochs.rs new file mode 100644 index 0000000000..b586a436c1 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.epochs.rs @@ -0,0 +1,284 @@ +// This file is @generated by prost-build. +/// EpochInfo stores metadata of an epoch timer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EpochInfo { + /// name is the unique identifier. + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + /// next_tick indicates when the next epoch starts (in Unix Epoch seconds), + /// if `EpochInfo` has been initialized. + /// If `EpochInfo` is not initialized yet, `next_tick` indicates the earliest + /// initialization time (see `is_initialized` below). + #[prost(uint32, tag = "2")] + pub next_tick: u32, + /// duration of the epoch in seconds. + #[prost(uint32, tag = "3")] + pub duration: u32, + /// current epoch is the number of the current epoch. + /// 0 if `next_tick` has never been reached, positive otherwise. + #[prost(uint32, tag = "4")] + pub current_epoch: u32, + /// current_epoch_start_block indicates the block height when the current + /// epoch started. 0 if `current_epoch` is 0. + #[prost(uint32, tag = "5")] + pub current_epoch_start_block: u32, + /// is_initialized indicates whether the `EpochInfo` has been initialized + /// and started ticking. + /// An `EpochInfo` is initialized when all below conditions are true: + /// - Not yet initialized + /// - `BlockHeight` >= 2 + /// - `BlockTime` >= `next_tick` + #[prost(bool, tag = "6")] + pub is_initialized: bool, + /// fast_forward_next_tick specifies whether during initialization, `next_tick` + /// should be fast-forwarded to be greater than the current block time. + /// If `false`, the original `next_tick` value is + /// unchanged during initialization. + /// If `true`, `next_tick` will be set to the smallest value `x` greater than + /// the current block time such that `(x - next_tick) % duration = 0`. + #[prost(bool, tag = "7")] + pub fast_forward_next_tick: bool, +} +impl ::prost::Name for EpochInfo { + const NAME: &'static str = "EpochInfo"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.EpochInfo".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.EpochInfo".into() + } +} +/// GenesisState defines the epochs module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// this line is used by starport scaffolding # genesis/proto/state + #[prost(message, repeated, tag = "1")] + pub epoch_info_list: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.GenesisState".into() + } +} +/// QueryGetEpochInfoRequest is request type for the GetEpochInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGetEpochInfoRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryGetEpochInfoRequest { + const NAME: &'static str = "QueryGetEpochInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.QueryGetEpochInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.QueryGetEpochInfoRequest".into() + } +} +/// QueryEpochInfoResponse is response type for the GetEpochInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEpochInfoResponse { + #[prost(message, optional, tag = "1")] + pub epoch_info: ::core::option::Option, +} +impl ::prost::Name for QueryEpochInfoResponse { + const NAME: &'static str = "QueryEpochInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.QueryEpochInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.QueryEpochInfoResponse".into() + } +} +/// QueryAllEpochInfoRequest is request type for the AllEpochInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllEpochInfoRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllEpochInfoRequest { + const NAME: &'static str = "QueryAllEpochInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.QueryAllEpochInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.QueryAllEpochInfoRequest".into() + } +} +/// QueryEpochInfoAllResponse is response type for the AllEpochInfo RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEpochInfoAllResponse { + #[prost(message, repeated, tag = "1")] + pub epoch_info: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryEpochInfoAllResponse { + const NAME: &'static str = "QueryEpochInfoAllResponse"; + const PACKAGE: &'static str = "dydxprotocol.epochs"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.epochs.QueryEpochInfoAllResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.epochs.QueryEpochInfoAllResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a EpochInfo by name. + pub async fn epoch_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.epochs.Query/EpochInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.epochs.Query", "EpochInfo")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of EpochInfo items. + pub async fn epoch_info_all( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.epochs.Query/EpochInfoAll", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.epochs.Query", "EpochInfoAll")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.feetiers.rs b/v4-proto-rs/src/dydxprotocol.feetiers.rs new file mode 100644 index 0000000000..36aa2256ae --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.feetiers.rs @@ -0,0 +1,436 @@ +// This file is @generated by prost-build. +/// PerpetualFeeParams defines the parameters for perpetual fees. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualFeeParams { + /// Sorted fee tiers (lowest requirements first). + #[prost(message, repeated, tag = "1")] + pub tiers: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for PerpetualFeeParams { + const NAME: &'static str = "PerpetualFeeParams"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.PerpetualFeeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.PerpetualFeeParams".into() + } +} +/// A fee tier for perpetuals +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualFeeTier { + /// Human-readable name of the tier, e.g. "Gold". + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + /// The trader's absolute volume requirement in quote quantums. + #[prost(uint64, tag = "2")] + pub absolute_volume_requirement: u64, + /// The total volume share requirement. + #[prost(uint32, tag = "3")] + pub total_volume_share_requirement_ppm: u32, + /// The maker volume share requirement. + #[prost(uint32, tag = "4")] + pub maker_volume_share_requirement_ppm: u32, + /// The maker fee once this tier is reached. + #[prost(sint32, tag = "5")] + pub maker_fee_ppm: i32, + /// The taker fee once this tier is reached. + #[prost(sint32, tag = "6")] + pub taker_fee_ppm: i32, +} +impl ::prost::Name for PerpetualFeeTier { + const NAME: &'static str = "PerpetualFeeTier"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.PerpetualFeeTier".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.PerpetualFeeTier".into() + } +} +/// GenesisState defines the feetiers module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The parameters for perpetual fees. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.GenesisState".into() + } +} +/// QueryPerpetualFeeParamsRequest is a request type for the PerpetualFeeParams +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPerpetualFeeParamsRequest {} +impl ::prost::Name for QueryPerpetualFeeParamsRequest { + const NAME: &'static str = "QueryPerpetualFeeParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.QueryPerpetualFeeParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.QueryPerpetualFeeParamsRequest".into() + } +} +/// QueryPerpetualFeeParamsResponse is a response type for the PerpetualFeeParams +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPerpetualFeeParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryPerpetualFeeParamsResponse { + const NAME: &'static str = "QueryPerpetualFeeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.QueryPerpetualFeeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.QueryPerpetualFeeParamsResponse".into() + } +} +/// QueryUserFeeTierRequest is a request type for the UserFeeTier RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryUserFeeTierRequest { + #[prost(string, tag = "1")] + pub user: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryUserFeeTierRequest { + const NAME: &'static str = "QueryUserFeeTierRequest"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.QueryUserFeeTierRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.QueryUserFeeTierRequest".into() + } +} +/// QueryUserFeeTierResponse is a request type for the UserFeeTier RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryUserFeeTierResponse { + /// Index of the fee tier in the list queried from PerpetualFeeParams. + #[prost(uint32, tag = "1")] + pub index: u32, + #[prost(message, optional, tag = "2")] + pub tier: ::core::option::Option, +} +impl ::prost::Name for QueryUserFeeTierResponse { + const NAME: &'static str = "QueryUserFeeTierResponse"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.QueryUserFeeTierResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.QueryUserFeeTierResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the PerpetualFeeParams. + pub async fn perpetual_fee_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.feetiers.Query/PerpetualFeeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.feetiers.Query", "PerpetualFeeParams"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries a user's fee tier + pub async fn user_fee_tier( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.feetiers.Query/UserFeeTier", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.feetiers.Query", "UserFeeTier")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgUpdatePerpetualFeeParams is the Msg/UpdatePerpetualFeeParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdatePerpetualFeeParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the parameters to update. All parameters must be supplied. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdatePerpetualFeeParams { + const NAME: &'static str = "MsgUpdatePerpetualFeeParams"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.MsgUpdatePerpetualFeeParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.MsgUpdatePerpetualFeeParams".into() + } +} +/// MsgUpdatePerpetualFeeParamsResponse is the Msg/UpdatePerpetualFeeParams +/// response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdatePerpetualFeeParamsResponse {} +impl ::prost::Name for MsgUpdatePerpetualFeeParamsResponse { + const NAME: &'static str = "MsgUpdatePerpetualFeeParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.feetiers"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.feetiers.MsgUpdatePerpetualFeeParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.feetiers.MsgUpdatePerpetualFeeParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// UpdatePerpetualFeeParams updates the PerpetualFeeParams in state. + pub async fn update_perpetual_fee_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.feetiers.Msg/UpdatePerpetualFeeParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.feetiers.Msg", + "UpdatePerpetualFeeParams", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.govplus.rs b/v4-proto-rs/src/dydxprotocol.govplus.rs new file mode 100644 index 0000000000..3d9b4e7aed --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.govplus.rs @@ -0,0 +1,275 @@ +// This file is @generated by prost-build. +/// GenesisState defines the govplus module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState {} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.govplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.govplus.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.govplus.GenesisState".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + } +} +/// MsgSlashValidator is the Msg/SlashValidator request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSlashValidator { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Consensus address of the validator to slash + #[prost(string, tag = "2")] + pub validator_address: ::prost::alloc::string::String, + /// Colloquially, the height at which the validator is deemed to have + /// misbehaved. In practice, this is the height used to determine the targets + /// of the slash. For example, undelegating after this height will not escape + /// slashing. This height should be set to a recent height at the time of the + /// proposal to prevent delegators from undelegating during the vote period. + /// i.e. infraction_height <= proposal submission height. + /// + /// NB: At the time this message is applied, this height must have occured + /// equal to or less than an unbonding period in the past in order for the + /// slash to be effective. + /// i.e. time(proposal pass height) - time(infraction_height) < unbonding + /// period + #[prost(uint32, tag = "3")] + pub infraction_height: u32, + /// Tokens of the validator at the specified height. Used to compute the slash + /// amount. The x/staking HistoricalInfo query endpoint can be used to find + /// this. + #[prost(bytes = "vec", tag = "4")] + pub tokens_at_infraction_height: ::prost::alloc::vec::Vec, + /// Multiplier for how much of the validator's stake should be slashed. + /// slash_factor * tokens_at_infraction_height = tokens slashed + #[prost(string, tag = "5")] + pub slash_factor: ::prost::alloc::string::String, +} +impl ::prost::Name for MsgSlashValidator { + const NAME: &'static str = "MsgSlashValidator"; + const PACKAGE: &'static str = "dydxprotocol.govplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.govplus.MsgSlashValidator".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.govplus.MsgSlashValidator".into() + } +} +/// MsgSlashValidatorResponse is the Msg/SlashValidator response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSlashValidatorResponse {} +impl ::prost::Name for MsgSlashValidatorResponse { + const NAME: &'static str = "MsgSlashValidatorResponse"; + const PACKAGE: &'static str = "dydxprotocol.govplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.govplus.MsgSlashValidatorResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.govplus.MsgSlashValidatorResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SlashValidator is exposed to allow slashing of a misbehaving validator via + /// governance. + pub async fn slash_validator( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.govplus.Msg/SlashValidator", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.govplus.Msg", "SlashValidator")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.events.rs b/v4-proto-rs/src/dydxprotocol.indexer.events.rs new file mode 100644 index 0000000000..a613801c76 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.events.rs @@ -0,0 +1,1046 @@ +// This file is @generated by prost-build. +/// FundingUpdate is used for funding update events and includes a funding +/// value and an optional funding index that correspond to a perpetual market. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FundingUpdateV1 { + /// The id of the perpetual market. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// funding value (in parts-per-million) can be premium vote, premium sample, + /// or funding rate. + #[prost(int32, tag = "2")] + pub funding_value_ppm: i32, + /// funding index is required if and only if parent `FundingEvent` type is + /// `TYPE_FUNDING_RATE_AND_INDEX`. + #[prost(bytes = "vec", tag = "3")] + pub funding_index: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for FundingUpdateV1 { + const NAME: &'static str = "FundingUpdateV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.FundingUpdateV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.FundingUpdateV1".into() + } +} +/// FundingEvent message contains a list of per-market funding values. The +/// funding values in the list is of the same type and the types are: which can +/// have one of the following types: +/// 1. Premium vote: votes on the premium values injected by block proposers. +/// 2. Premium sample: combined value from all premium votes during a +/// `funding-sample` epoch. +/// 3. Funding rate and index: final funding rate combining all premium samples +/// during a `funding-tick` epoch and funding index accordingly updated with +/// `funding rate * price`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FundingEventV1 { + /// updates is a list of per-market funding updates for all existing perpetual + /// markets. The list is sorted by `perpetualId`s which are unique. + #[prost(message, repeated, tag = "1")] + pub updates: ::prost::alloc::vec::Vec, + /// type stores the type of funding updates. + #[prost(enumeration = "funding_event_v1::Type", tag = "2")] + pub r#type: i32, +} +/// Nested message and enum types in `FundingEventV1`. +pub mod funding_event_v1 { + /// Type is the type for funding values. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Type { + /// Unspecified type. + Unspecified = 0, + /// Premium sample is the combined value from all premium votes during a + /// `funding-sample` epoch. + PremiumSample = 1, + /// Funding rate is the final funding rate combining all premium samples + /// during a `funding-tick` epoch. + FundingRateAndIndex = 2, + /// TODO(DEC-1513): Investigate whether premium vote values need to be + /// sent to indexer. + PremiumVote = 3, + } + impl Type { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Type::Unspecified => "TYPE_UNSPECIFIED", + Type::PremiumSample => "TYPE_PREMIUM_SAMPLE", + Type::FundingRateAndIndex => "TYPE_FUNDING_RATE_AND_INDEX", + Type::PremiumVote => "TYPE_PREMIUM_VOTE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "TYPE_PREMIUM_SAMPLE" => Some(Self::PremiumSample), + "TYPE_FUNDING_RATE_AND_INDEX" => Some(Self::FundingRateAndIndex), + "TYPE_PREMIUM_VOTE" => Some(Self::PremiumVote), + _ => None, + } + } + } +} +impl ::prost::Name for FundingEventV1 { + const NAME: &'static str = "FundingEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.FundingEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.FundingEventV1".into() + } +} +/// MarketEvent message contains all the information about a market event on +/// the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketEventV1 { + /// market id. + #[prost(uint32, tag = "1")] + pub market_id: u32, + /// either an event for price update, market creation, or market modification. + #[prost(oneof = "market_event_v1::Event", tags = "2, 3, 4")] + pub event: ::core::option::Option, +} +/// Nested message and enum types in `MarketEventV1`. +pub mod market_event_v1 { + /// either an event for price update, market creation, or market modification. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Event { + #[prost(message, tag = "2")] + PriceUpdate(super::MarketPriceUpdateEventV1), + #[prost(message, tag = "3")] + MarketCreate(super::MarketCreateEventV1), + #[prost(message, tag = "4")] + MarketModify(super::MarketModifyEventV1), + } +} +impl ::prost::Name for MarketEventV1 { + const NAME: &'static str = "MarketEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.MarketEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.MarketEventV1".into() + } +} +/// MarketPriceUpdateEvent message contains all the information about a price +/// update on the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketPriceUpdateEventV1 { + /// price_with_exponent. Multiply by 10 ^ Exponent to get the human readable + /// price in dollars. For example if `Exponent == -5` then a `exponent_price` + /// of `1,000,000,000` represents “$10,000`. + #[prost(uint64, tag = "1")] + pub price_with_exponent: u64, +} +impl ::prost::Name for MarketPriceUpdateEventV1 { + const NAME: &'static str = "MarketPriceUpdateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.MarketPriceUpdateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.MarketPriceUpdateEventV1".into() + } +} +/// shared fields between MarketCreateEvent and MarketModifyEvent +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketBaseEventV1 { + /// String representation of the market pair, e.g. `BTC-USD` + #[prost(string, tag = "1")] + pub pair: ::prost::alloc::string::String, + /// The minimum allowable change in the Price value for a given update. + /// Measured as 1e-6. + #[prost(uint32, tag = "2")] + pub min_price_change_ppm: u32, +} +impl ::prost::Name for MarketBaseEventV1 { + const NAME: &'static str = "MarketBaseEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.MarketBaseEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.MarketBaseEventV1".into() + } +} +/// MarketCreateEvent message contains all the information about a new market on +/// the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketCreateEventV1 { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + /// Static value. The exponent of the price. + /// For example if Exponent == -5 then a `exponent_price` of 1,000,000,000 + /// represents $10,000. Therefore 10 ^ Exponent represents the smallest + /// price step (in dollars) that can be recorded. + #[prost(sint32, tag = "2")] + pub exponent: i32, +} +impl ::prost::Name for MarketCreateEventV1 { + const NAME: &'static str = "MarketCreateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.MarketCreateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.MarketCreateEventV1".into() + } +} +/// MarketModifyEvent message contains all the information about a market update +/// on the dYdX chain +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketModifyEventV1 { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, +} +impl ::prost::Name for MarketModifyEventV1 { + const NAME: &'static str = "MarketModifyEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.MarketModifyEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.MarketModifyEventV1".into() + } +} +/// SourceOfFunds is the source of funds in a transfer event. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SourceOfFunds { + /// one of below + /// - a subaccount ID + /// - a wallet address + #[prost(oneof = "source_of_funds::Source", tags = "1, 2")] + pub source: ::core::option::Option, +} +/// Nested message and enum types in `SourceOfFunds`. +pub mod source_of_funds { + /// one of below + /// - a subaccount ID + /// - a wallet address + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Source { + #[prost(message, tag = "1")] + SubaccountId(super::super::protocol::v1::IndexerSubaccountId), + #[prost(string, tag = "2")] + Address(::prost::alloc::string::String), + } +} +impl ::prost::Name for SourceOfFunds { + const NAME: &'static str = "SourceOfFunds"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.SourceOfFunds".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.SourceOfFunds".into() + } +} +/// TransferEvent message contains all the information about a transfer, +/// deposit-to-subaccount, or withdraw-from-subaccount on the dYdX chain. +/// When a subaccount is involved, a SubaccountUpdateEvent message will +/// be produced with the updated asset positions. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferEventV1 { + #[prost(message, optional, tag = "1")] + pub sender_subaccount_id: ::core::option::Option< + super::protocol::v1::IndexerSubaccountId, + >, + #[prost(message, optional, tag = "2")] + pub recipient_subaccount_id: ::core::option::Option< + super::protocol::v1::IndexerSubaccountId, + >, + /// Id of the asset transfered. + #[prost(uint32, tag = "3")] + pub asset_id: u32, + /// The amount of asset in quantums to transfer. + #[prost(uint64, tag = "4")] + pub amount: u64, + /// The sender is one of below + /// - a subaccount ID (in transfer and withdraw events). + /// - a wallet address (in deposit events). + #[prost(message, optional, tag = "5")] + pub sender: ::core::option::Option, + /// The recipient is one of below + /// - a subaccount ID (in transfer and deposit events). + /// - a wallet address (in withdraw events). + #[prost(message, optional, tag = "6")] + pub recipient: ::core::option::Option, +} +impl ::prost::Name for TransferEventV1 { + const NAME: &'static str = "TransferEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.TransferEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.TransferEventV1".into() + } +} +/// OrderFillEvent message contains all the information from an order match in +/// the dYdX chain. This includes the maker/taker orders that matched and the +/// amount filled. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderFillEventV1 { + #[prost(message, optional, tag = "1")] + pub maker_order: ::core::option::Option, + /// Fill amount in base quantums. + #[prost(uint64, tag = "3")] + pub fill_amount: u64, + /// Maker fee in USDC quantums. + #[prost(sint64, tag = "5")] + pub maker_fee: i64, + /// Taker fee in USDC quantums. If the taker order is a liquidation, then this + /// represents the special liquidation fee, not the standard taker fee. + #[prost(sint64, tag = "6")] + pub taker_fee: i64, + /// Total filled of the maker order in base quantums. + #[prost(uint64, tag = "7")] + pub total_filled_maker: u64, + /// Total filled of the taker order in base quantums. + #[prost(uint64, tag = "8")] + pub total_filled_taker: u64, + /// The type of order fill this event represents. + #[prost(oneof = "order_fill_event_v1::TakerOrder", tags = "2, 4")] + pub taker_order: ::core::option::Option, +} +/// Nested message and enum types in `OrderFillEventV1`. +pub mod order_fill_event_v1 { + /// The type of order fill this event represents. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum TakerOrder { + #[prost(message, tag = "2")] + Order(super::super::protocol::v1::IndexerOrder), + #[prost(message, tag = "4")] + LiquidationOrder(super::LiquidationOrderV1), + } +} +impl ::prost::Name for OrderFillEventV1 { + const NAME: &'static str = "OrderFillEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.OrderFillEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.OrderFillEventV1".into() + } +} +/// DeleveragingEvent message contains all the information for a deleveraging +/// on the dYdX chain. This includes the liquidated/offsetting subaccounts and +/// the amount filled. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleveragingEventV1 { + /// ID of the subaccount that was liquidated. + #[prost(message, optional, tag = "1")] + pub liquidated: ::core::option::Option, + /// ID of the subaccount that was used to offset the position. + #[prost(message, optional, tag = "2")] + pub offsetting: ::core::option::Option, + /// The ID of the perpetual that was liquidated. + #[prost(uint32, tag = "3")] + pub perpetual_id: u32, + /// The amount filled between the liquidated and offsetting position, in + /// base quantums. + #[prost(uint64, tag = "4")] + pub fill_amount: u64, + /// Total quote quantums filled. + #[prost(uint64, tag = "5")] + pub total_quote_quantums: u64, + /// `true` if liquidating a short position, `false` otherwise. + #[prost(bool, tag = "6")] + pub is_buy: bool, + /// `true` if the deleveraging event is for final settlement, indicating + /// the match occurred at the oracle price rather than bankruptcy price. + /// When this flag is `false`, the fill price is the bankruptcy price + /// of the liquidated subaccount. + #[prost(bool, tag = "7")] + pub is_final_settlement: bool, +} +impl ::prost::Name for DeleveragingEventV1 { + const NAME: &'static str = "DeleveragingEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.DeleveragingEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.DeleveragingEventV1".into() + } +} +/// LiquidationOrder represents the liquidation taker order to be included in a +/// liquidation order fill event. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidationOrderV1 { + /// ID of the subaccount that was liquidated. + #[prost(message, optional, tag = "1")] + pub liquidated: ::core::option::Option, + /// The ID of the clob pair involved in the liquidation. + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// The ID of the perpetual involved in the liquidation. + #[prost(uint32, tag = "3")] + pub perpetual_id: u32, + /// The total size of the liquidation order including any unfilled size, + /// in base quantums. + #[prost(uint64, tag = "4")] + pub total_size: u64, + /// `true` if liquidating a short position, `false` otherwise. + #[prost(bool, tag = "5")] + pub is_buy: bool, + /// The fillable price in subticks. + /// This represents the lower-price-bound for liquidating longs + /// and the upper-price-bound for liquidating shorts. + /// Must be a multiple of ClobPair.SubticksPerTick + /// (where `ClobPair.Id = orderId.ClobPairId`). + #[prost(uint64, tag = "6")] + pub subticks: u64, +} +impl ::prost::Name for LiquidationOrderV1 { + const NAME: &'static str = "LiquidationOrderV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.LiquidationOrderV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.LiquidationOrderV1".into() + } +} +/// SubaccountUpdateEvent message contains information about an update to a +/// subaccount in the dYdX chain. This includes the list of updated perpetual +/// and asset positions for the subaccount. +/// Note: This event message will contain all the updates to a subaccount +/// at the end of a block which is why multiple asset/perpetual position +/// updates may exist. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountUpdateEventV1 { + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// updated_perpetual_positions will each be for unique perpetuals. + #[prost(message, repeated, tag = "3")] + pub updated_perpetual_positions: ::prost::alloc::vec::Vec< + super::protocol::v1::IndexerPerpetualPosition, + >, + /// updated_asset_positions will each be for unique assets. + #[prost(message, repeated, tag = "4")] + pub updated_asset_positions: ::prost::alloc::vec::Vec< + super::protocol::v1::IndexerAssetPosition, + >, +} +impl ::prost::Name for SubaccountUpdateEventV1 { + const NAME: &'static str = "SubaccountUpdateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.SubaccountUpdateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.SubaccountUpdateEventV1".into() + } +} +/// StatefulOrderEvent message contains information about a change to a stateful +/// order. Currently, this is either the placement of a long-term order, the +/// placement or triggering of a conditional order, or the removal of a +/// stateful order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatefulOrderEventV1 { + /// The type of event that this StatefulOrderEvent contains. + #[prost(oneof = "stateful_order_event_v1::Event", tags = "1, 4, 5, 6, 7, 8")] + pub event: ::core::option::Option, +} +/// Nested message and enum types in `StatefulOrderEventV1`. +pub mod stateful_order_event_v1 { + /// A stateful order placement contains an order. + /// Deprecated in favor of LongTermOrderPlacementV1. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct StatefulOrderPlacementV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + } + impl ::prost::Name for StatefulOrderPlacementV1 { + const NAME: &'static str = "StatefulOrderPlacementV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.StatefulOrderPlacementV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.StatefulOrderPlacementV1" + .into() + } + } + /// A stateful order removal contains the id of an order that was already + /// placed and is now removed and the reason for the removal. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct StatefulOrderRemovalV1 { + #[prost(message, optional, tag = "1")] + pub removed_order_id: ::core::option::Option< + super::super::protocol::v1::IndexerOrderId, + >, + #[prost(enumeration = "super::super::shared::OrderRemovalReason", tag = "2")] + pub reason: i32, + } + impl ::prost::Name for StatefulOrderRemovalV1 { + const NAME: &'static str = "StatefulOrderRemovalV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.StatefulOrderRemovalV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.StatefulOrderRemovalV1" + .into() + } + } + /// A conditional order placement contains an order. The order is newly-placed + /// and untriggered when this event is emitted. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ConditionalOrderPlacementV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + } + impl ::prost::Name for ConditionalOrderPlacementV1 { + const NAME: &'static str = "ConditionalOrderPlacementV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.ConditionalOrderPlacementV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.ConditionalOrderPlacementV1" + .into() + } + } + /// A conditional order trigger event contains an order id and is emitted when + /// an order is triggered. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ConditionalOrderTriggeredV1 { + #[prost(message, optional, tag = "1")] + pub triggered_order_id: ::core::option::Option< + super::super::protocol::v1::IndexerOrderId, + >, + } + impl ::prost::Name for ConditionalOrderTriggeredV1 { + const NAME: &'static str = "ConditionalOrderTriggeredV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.ConditionalOrderTriggeredV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.ConditionalOrderTriggeredV1" + .into() + } + } + /// A long term order placement contains an order. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LongTermOrderPlacementV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + } + impl ::prost::Name for LongTermOrderPlacementV1 { + const NAME: &'static str = "LongTermOrderPlacementV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.LongTermOrderPlacementV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.LongTermOrderPlacementV1" + .into() + } + } + /// A long term order placement contains an order. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LongTermOrderReplacementV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + } + impl ::prost::Name for LongTermOrderReplacementV1 { + const NAME: &'static str = "LongTermOrderReplacementV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1.LongTermOrderReplacementV1" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1.LongTermOrderReplacementV1" + .into() + } + } + /// The type of event that this StatefulOrderEvent contains. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Event { + /// Deprecated in favor of long_term_order_placement + #[prost(message, tag = "1")] + OrderPlace(StatefulOrderPlacementV1), + #[prost(message, tag = "4")] + OrderRemoval(StatefulOrderRemovalV1), + #[prost(message, tag = "5")] + ConditionalOrderPlacement(ConditionalOrderPlacementV1), + #[prost(message, tag = "6")] + ConditionalOrderTriggered(ConditionalOrderTriggeredV1), + #[prost(message, tag = "7")] + LongTermOrderPlacement(LongTermOrderPlacementV1), + #[prost(message, tag = "8")] + OrderReplace(LongTermOrderReplacementV1), + } +} +impl ::prost::Name for StatefulOrderEventV1 { + const NAME: &'static str = "StatefulOrderEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.StatefulOrderEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.StatefulOrderEventV1".into() + } +} +/// AssetCreateEventV1 message contains all the information about an new Asset on +/// the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssetCreateEventV1 { + /// Unique, sequentially-generated. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The human readable symbol of the `Asset` (e.g. `USDC`, `ATOM`). + /// Must be uppercase, unique and correspond to the canonical symbol of the + /// full coin. + #[prost(string, tag = "2")] + pub symbol: ::prost::alloc::string::String, + /// `true` if this `Asset` has a valid `MarketId` value. + #[prost(bool, tag = "3")] + pub has_market: bool, + /// The `Id` of the `Market` associated with this `Asset`. It acts as the + /// oracle price for the purposes of calculating collateral + /// and margin requirements. + #[prost(uint32, tag = "4")] + pub market_id: u32, + /// The exponent for converting an atomic amount (1 'quantum') + /// to a full coin. For example, if `atomic_resolution = -8` + /// then an `asset_position` with `base_quantums = 1e8` is equivalent to + /// a position size of one full coin. + #[prost(sint32, tag = "5")] + pub atomic_resolution: i32, +} +impl ::prost::Name for AssetCreateEventV1 { + const NAME: &'static str = "AssetCreateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.AssetCreateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.AssetCreateEventV1".into() + } +} +/// PerpetualMarketCreateEventV1 message contains all the information about a +/// new Perpetual Market on the dYdX chain. +/// Deprecated. See PerpetualMarketCreateEventV2 for the most up to date message +/// for the event to create a new Perpetual Market. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualMarketCreateEventV1 { + /// Unique Perpetual id. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "1")] + pub id: u32, + /// Unique clob pair Id associated with this perpetual market + /// Defined in clob.clob_pair + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// The name of the `Perpetual` (e.g. `BTC-USD`). + /// Defined in perpetuals.perpetual + #[prost(string, tag = "3")] + pub ticker: ::prost::alloc::string::String, + /// Unique id of market param associated with this perpetual market. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "4")] + pub market_id: u32, + /// Status of the CLOB + #[prost(enumeration = "super::protocol::v1::ClobPairStatus", tag = "5")] + pub status: i32, + /// `10^Exponent` gives the number of QuoteQuantums traded per BaseQuantum + /// per Subtick. + /// Defined in clob.clob_pair + #[prost(sint32, tag = "6")] + pub quantum_conversion_exponent: i32, + /// The exponent for converting an atomic amount (`size = 1`) + /// to a full coin. For example, if `AtomicResolution = -8` + /// then a `PerpetualPosition` with `size = 1e8` is equivalent to + /// a position size of one full coin. + /// Defined in perpetuals.perpetual + #[prost(sint32, tag = "7")] + pub atomic_resolution: i32, + /// Defines the tick size of the orderbook by defining how many subticks + /// are in one tick. That is, the subticks of any valid order must be a + /// multiple of this value. Generally this value should start `>= 100`to + /// allow room for decreasing it. + /// Defined in clob.clob_pair + #[prost(uint32, tag = "8")] + pub subticks_per_tick: u32, + /// Minimum increment in the size of orders on the CLOB, in base quantums. + /// Defined in clob.clob_pair + #[prost(uint64, tag = "9")] + pub step_base_quantums: u64, + /// The liquidity_tier that this perpetual is associated with. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "10")] + pub liquidity_tier: u32, +} +impl ::prost::Name for PerpetualMarketCreateEventV1 { + const NAME: &'static str = "PerpetualMarketCreateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.PerpetualMarketCreateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.PerpetualMarketCreateEventV1".into() + } +} +/// PerpetualMarketCreateEventV2 message contains all the information about a +/// new Perpetual Market on the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualMarketCreateEventV2 { + /// Unique Perpetual id. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "1")] + pub id: u32, + /// Unique clob pair Id associated with this perpetual market + /// Defined in clob.clob_pair + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// The name of the `Perpetual` (e.g. `BTC-USD`). + /// Defined in perpetuals.perpetual + #[prost(string, tag = "3")] + pub ticker: ::prost::alloc::string::String, + /// Unique id of market param associated with this perpetual market. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "4")] + pub market_id: u32, + /// Status of the CLOB + #[prost(enumeration = "super::protocol::v1::ClobPairStatus", tag = "5")] + pub status: i32, + /// `10^Exponent` gives the number of QuoteQuantums traded per BaseQuantum + /// per Subtick. + /// Defined in clob.clob_pair + #[prost(sint32, tag = "6")] + pub quantum_conversion_exponent: i32, + /// The exponent for converting an atomic amount (`size = 1`) + /// to a full coin. For example, if `AtomicResolution = -8` + /// then a `PerpetualPosition` with `size = 1e8` is equivalent to + /// a position size of one full coin. + /// Defined in perpetuals.perpetual + #[prost(sint32, tag = "7")] + pub atomic_resolution: i32, + /// Defines the tick size of the orderbook by defining how many subticks + /// are in one tick. That is, the subticks of any valid order must be a + /// multiple of this value. Generally this value should start `>= 100`to + /// allow room for decreasing it. + /// Defined in clob.clob_pair + #[prost(uint32, tag = "8")] + pub subticks_per_tick: u32, + /// Minimum increment in the size of orders on the CLOB, in base quantums. + /// Defined in clob.clob_pair + #[prost(uint64, tag = "9")] + pub step_base_quantums: u64, + /// The liquidity_tier that this perpetual is associated with. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "10")] + pub liquidity_tier: u32, + /// Market type of the perpetual. + #[prost(enumeration = "super::protocol::v1::PerpetualMarketType", tag = "11")] + pub market_type: i32, +} +impl ::prost::Name for PerpetualMarketCreateEventV2 { + const NAME: &'static str = "PerpetualMarketCreateEventV2"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.PerpetualMarketCreateEventV2".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.PerpetualMarketCreateEventV2".into() + } +} +/// LiquidityTierUpsertEventV1 message contains all the information to +/// create/update a Liquidity Tier on the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidityTierUpsertEventV1 { + /// Unique id. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The name of the tier purely for mnemonic purposes, e.g. "Gold". + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + /// The margin fraction needed to open a position. + /// In parts-per-million. + #[prost(uint32, tag = "3")] + pub initial_margin_ppm: u32, + /// The fraction of the initial-margin that the maintenance-margin is, + /// e.g. 50%. In parts-per-million. + #[prost(uint32, tag = "4")] + pub maintenance_fraction_ppm: u32, + /// The maximum position size at which the margin requirements are + /// not increased over the default values. Above this position size, + /// the margin requirements increase at a rate of sqrt(size). + /// + /// Deprecated since v3.x. + #[deprecated] + #[prost(uint64, tag = "5")] + pub base_position_notional: u64, +} +impl ::prost::Name for LiquidityTierUpsertEventV1 { + const NAME: &'static str = "LiquidityTierUpsertEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.LiquidityTierUpsertEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.LiquidityTierUpsertEventV1".into() + } +} +/// UpdateClobPairEventV1 message contains all the information about an update to +/// a clob pair on the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateClobPairEventV1 { + /// Unique clob pair Id associated with this perpetual market + /// Defined in clob.clob_pair + #[prost(uint32, tag = "1")] + pub clob_pair_id: u32, + /// Status of the CLOB + #[prost(enumeration = "super::protocol::v1::ClobPairStatus", tag = "2")] + pub status: i32, + /// `10^Exponent` gives the number of QuoteQuantums traded per BaseQuantum + /// per Subtick. + /// Defined in clob.clob_pair + #[prost(sint32, tag = "3")] + pub quantum_conversion_exponent: i32, + /// Defines the tick size of the orderbook by defining how many subticks + /// are in one tick. That is, the subticks of any valid order must be a + /// multiple of this value. Generally this value should start `>= 100`to + /// allow room for decreasing it. + /// Defined in clob.clob_pair + #[prost(uint32, tag = "4")] + pub subticks_per_tick: u32, + /// Minimum increment in the size of orders on the CLOB, in base quantums. + /// Defined in clob.clob_pair + #[prost(uint64, tag = "5")] + pub step_base_quantums: u64, +} +impl ::prost::Name for UpdateClobPairEventV1 { + const NAME: &'static str = "UpdateClobPairEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.UpdateClobPairEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.UpdateClobPairEventV1".into() + } +} +/// UpdatePerpetualEventV1 message contains all the information about an update +/// to a perpetual on the dYdX chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdatePerpetualEventV1 { + /// Unique Perpetual id. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "1")] + pub id: u32, + /// The name of the `Perpetual` (e.g. `BTC-USD`). + /// Defined in perpetuals.perpetual + #[prost(string, tag = "2")] + pub ticker: ::prost::alloc::string::String, + /// Unique id of market param associated with this perpetual market. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "3")] + pub market_id: u32, + /// The exponent for converting an atomic amount (`size = 1`) + /// to a full coin. For example, if `AtomicResolution = -8` + /// then a `PerpetualPosition` with `size = 1e8` is equivalent to + /// a position size of one full coin. + /// Defined in perpetuals.perpetual + #[prost(sint32, tag = "4")] + pub atomic_resolution: i32, + /// The liquidity_tier that this perpetual is associated with. + /// Defined in perpetuals.perpetual + #[prost(uint32, tag = "5")] + pub liquidity_tier: u32, +} +impl ::prost::Name for UpdatePerpetualEventV1 { + const NAME: &'static str = "UpdatePerpetualEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.UpdatePerpetualEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.UpdatePerpetualEventV1".into() + } +} +/// TradingRewardsEventV1 is communicates all trading rewards for all accounts +/// that receive trade rewards in the block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TradingRewardsEventV1 { + /// The list of all trading rewards in the block. + #[prost(message, repeated, tag = "1")] + pub trading_rewards: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for TradingRewardsEventV1 { + const NAME: &'static str = "TradingRewardsEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.TradingRewardsEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.TradingRewardsEventV1".into() + } +} +/// AddressTradingReward contains info on an instance of an address receiving a +/// reward +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddressTradingReward { + /// The address of the wallet that will receive the trading reward. + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + /// The amount of trading rewards earned by the address above in denoms. 1e18 + /// denoms is equivalent to a single coin. + #[prost(bytes = "vec", tag = "2")] + pub denom_amount: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AddressTradingReward { + const NAME: &'static str = "AddressTradingReward"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.AddressTradingReward".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.AddressTradingReward".into() + } +} +/// OpenInterestUpdateEventV1 is used for open interest update events +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenInterestUpdateEventV1 { + /// The list of all open interest updates in the block. + #[prost(message, repeated, tag = "1")] + pub open_interest_updates: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for OpenInterestUpdateEventV1 { + const NAME: &'static str = "OpenInterestUpdateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.OpenInterestUpdateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.OpenInterestUpdateEventV1".into() + } +} +/// OpenInterestUpdate contains a single open interest update for a perpetual +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenInterestUpdate { + /// The ID of the perpetual market. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The new open interest value for the perpetual market. + #[prost(bytes = "vec", tag = "2")] + pub open_interest: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for OpenInterestUpdate { + const NAME: &'static str = "OpenInterestUpdate"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.OpenInterestUpdate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.OpenInterestUpdate".into() + } +} +/// LiquidationEventV2 message contains all the information needed to update +/// the liquidity tiers. It contains all the fields from V1 along with the +/// open interest caps. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidityTierUpsertEventV2 { + /// Unique id. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The name of the tier purely for mnemonic purposes, e.g. "Gold". + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + /// The margin fraction needed to open a position. + /// In parts-per-million. + #[prost(uint32, tag = "3")] + pub initial_margin_ppm: u32, + /// The fraction of the initial-margin that the maintenance-margin is, + /// e.g. 50%. In parts-per-million. + #[prost(uint32, tag = "4")] + pub maintenance_fraction_ppm: u32, + /// The maximum position size at which the margin requirements are + /// not increased over the default values. Above this position size, + /// the margin requirements increase at a rate of sqrt(size). + /// + /// Deprecated since v3.x. + #[deprecated] + #[prost(uint64, tag = "5")] + pub base_position_notional: u64, + /// Lower cap of open interest in quote quantums. optional + #[prost(uint64, tag = "6")] + pub open_interest_lower_cap: u64, + /// Upper cap of open interest in quote quantums. + #[prost(uint64, tag = "7")] + pub open_interest_upper_cap: u64, +} +impl ::prost::Name for LiquidityTierUpsertEventV2 { + const NAME: &'static str = "LiquidityTierUpsertEventV2"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.LiquidityTierUpsertEventV2".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.LiquidityTierUpsertEventV2".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs b/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs new file mode 100644 index 0000000000..4403e6bb5e --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs @@ -0,0 +1,162 @@ +// This file is @generated by prost-build. +/// IndexerTendermintEventWrapper is a wrapper around IndexerTendermintEvent, +/// with an additional txn_hash field. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerTendermintEventWrapper { + #[prost(message, optional, tag = "1")] + pub event: ::core::option::Option, + #[prost(string, tag = "2")] + pub txn_hash: ::prost::alloc::string::String, +} +impl ::prost::Name for IndexerTendermintEventWrapper { + const NAME: &'static str = "IndexerTendermintEventWrapper"; + const PACKAGE: &'static str = "dydxprotocol.indexer.indexer_manager"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.indexer_manager.IndexerTendermintEventWrapper".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.indexer_manager.IndexerTendermintEventWrapper".into() + } +} +/// IndexerEventsStoreValue represents the type of the value of the +/// `IndexerEventsStore` in state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerEventsStoreValue { + #[prost(message, repeated, tag = "1")] + pub events: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for IndexerEventsStoreValue { + const NAME: &'static str = "IndexerEventsStoreValue"; + const PACKAGE: &'static str = "dydxprotocol.indexer.indexer_manager"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.indexer_manager.IndexerEventsStoreValue".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.indexer_manager.IndexerEventsStoreValue".into() + } +} +/// IndexerTendermintEvent contains the base64 encoded event proto emitted from +/// the dYdX application as well as additional metadata to determine the ordering +/// of the event within the block and the subtype of the event. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerTendermintEvent { + /// Subtype of the event e.g. "order_fill", "subaccount_update", etc. + #[prost(string, tag = "1")] + pub subtype: ::prost::alloc::string::String, + /// Index of the event within the list of events that happened either during a + /// transaction or during processing of a block. + /// TODO(DEC-537): Deprecate this field because events are already ordered. + #[prost(uint32, tag = "5")] + pub event_index: u32, + /// Version of the event. + #[prost(uint32, tag = "6")] + pub version: u32, + /// Tendermint event bytes. + #[prost(bytes = "vec", tag = "7")] + pub data_bytes: ::prost::alloc::vec::Vec, + /// ordering_within_block is either the transaction index or a boolean + /// indicating the event was generated during processing the block rather than + /// any specific transaction e.g. during FinalizeBlock. + #[prost(oneof = "indexer_tendermint_event::OrderingWithinBlock", tags = "3, 4")] + pub ordering_within_block: ::core::option::Option< + indexer_tendermint_event::OrderingWithinBlock, + >, +} +/// Nested message and enum types in `IndexerTendermintEvent`. +pub mod indexer_tendermint_event { + /// enum to specify that the IndexerTendermintEvent is a block event. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum BlockEvent { + /// Default value. This value is invalid and unused. + Unspecified = 0, + /// BLOCK_EVENT_BEGIN_BLOCK indicates that the event was generated during + /// BeginBlock. + BeginBlock = 1, + /// BLOCK_EVENT_END_BLOCK indicates that the event was generated during + /// EndBlock. + EndBlock = 2, + } + impl BlockEvent { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + BlockEvent::Unspecified => "BLOCK_EVENT_UNSPECIFIED", + BlockEvent::BeginBlock => "BLOCK_EVENT_BEGIN_BLOCK", + BlockEvent::EndBlock => "BLOCK_EVENT_END_BLOCK", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "BLOCK_EVENT_UNSPECIFIED" => Some(Self::Unspecified), + "BLOCK_EVENT_BEGIN_BLOCK" => Some(Self::BeginBlock), + "BLOCK_EVENT_END_BLOCK" => Some(Self::EndBlock), + _ => None, + } + } + } + /// ordering_within_block is either the transaction index or a boolean + /// indicating the event was generated during processing the block rather than + /// any specific transaction e.g. during FinalizeBlock. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum OrderingWithinBlock { + #[prost(uint32, tag = "3")] + TransactionIndex(u32), + #[prost(enumeration = "BlockEvent", tag = "4")] + BlockEvent(i32), + } +} +impl ::prost::Name for IndexerTendermintEvent { + const NAME: &'static str = "IndexerTendermintEvent"; + const PACKAGE: &'static str = "dydxprotocol.indexer.indexer_manager"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.indexer_manager.IndexerTendermintEvent".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.indexer_manager.IndexerTendermintEvent".into() + } +} +/// IndexerTendermintBlock contains all the events for the block along with +/// metadata for the block height, timestamp of the block and a list of all the +/// hashes of the transactions within the block. The transaction hashes follow +/// the ordering of the transactions as they appear within the block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerTendermintBlock { + #[prost(uint32, tag = "1")] + pub height: u32, + #[prost(message, optional, tag = "2")] + pub time: ::core::option::Option<::prost_types::Timestamp>, + #[prost(message, repeated, tag = "3")] + pub events: ::prost::alloc::vec::Vec, + #[prost(string, repeated, tag = "4")] + pub tx_hashes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +impl ::prost::Name for IndexerTendermintBlock { + const NAME: &'static str = "IndexerTendermintBlock"; + const PACKAGE: &'static str = "dydxprotocol.indexer.indexer_manager"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.indexer_manager.IndexerTendermintBlock".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.indexer_manager.IndexerTendermintBlock".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs b/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs new file mode 100644 index 0000000000..56dd4cda0a --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs @@ -0,0 +1,256 @@ +// This file is @generated by prost-build. +/// OrderPlace messages contain the order placed/replaced. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderPlaceV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + #[prost(enumeration = "order_place_v1::OrderPlacementStatus", tag = "2")] + pub placement_status: i32, + /// The timestamp of the order placement. + #[prost(message, optional, tag = "3")] + pub time_stamp: ::core::option::Option<::prost_types::Timestamp>, +} +/// Nested message and enum types in `OrderPlaceV1`. +pub mod order_place_v1 { + /// OrderPlacementStatus is an enum for the resulting status after an order is + /// placed. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum OrderPlacementStatus { + /// Default value, this is invalid and unused. + Unspecified = 0, + /// A best effort opened order is one that has only been confirmed to be + /// placed on the dYdX node sending the off-chain update message. + /// The cases where this happens includes: + /// - The dYdX node places an order in it's in-memory orderbook during the + /// CheckTx flow. + /// A best effort placed order may not have been placed on other dYdX + /// nodes including other dYdX validator nodes and may still be excluded in + /// future order matches. + BestEffortOpened = 1, + /// An opened order is one that is confirmed to be placed on all dYdX nodes + /// (discounting dishonest dYdX nodes) and will be included in any future + /// order matches. + /// This status is used internally by the indexer and will not be sent + /// out by protocol. + Opened = 2, + } + impl OrderPlacementStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OrderPlacementStatus::Unspecified => "ORDER_PLACEMENT_STATUS_UNSPECIFIED", + OrderPlacementStatus::BestEffortOpened => { + "ORDER_PLACEMENT_STATUS_BEST_EFFORT_OPENED" + } + OrderPlacementStatus::Opened => "ORDER_PLACEMENT_STATUS_OPENED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ORDER_PLACEMENT_STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "ORDER_PLACEMENT_STATUS_BEST_EFFORT_OPENED" => { + Some(Self::BestEffortOpened) + } + "ORDER_PLACEMENT_STATUS_OPENED" => Some(Self::Opened), + _ => None, + } + } + } +} +impl ::prost::Name for OrderPlaceV1 { + const NAME: &'static str = "OrderPlaceV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.off_chain_updates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.off_chain_updates.OrderPlaceV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.off_chain_updates.OrderPlaceV1".into() + } +} +/// OrderRemove messages contain the id of the order removed, the reason for the +/// removal and the resulting status from the removal. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderRemoveV1 { + #[prost(message, optional, tag = "1")] + pub removed_order_id: ::core::option::Option, + #[prost(enumeration = "super::shared::OrderRemovalReason", tag = "2")] + pub reason: i32, + #[prost(enumeration = "order_remove_v1::OrderRemovalStatus", tag = "3")] + pub removal_status: i32, + /// The timestamp of the order removal. + #[prost(message, optional, tag = "4")] + pub time_stamp: ::core::option::Option<::prost_types::Timestamp>, +} +/// Nested message and enum types in `OrderRemoveV1`. +pub mod order_remove_v1 { + /// OrderRemovalStatus is an enum for the resulting status after an order is + /// removed. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum OrderRemovalStatus { + /// Default value, this is invalid and unused. + Unspecified = 0, + /// A best effort canceled order is one that has only been confirmed to be + /// removed on the dYdX node sending the off-chain update message. + /// The cases where this happens includes: + /// - the order was removed due to the dYdX node receiving a CancelOrder + /// transaction for the order. + /// - the order was removed due to being undercollateralized during + /// optimistic matching. + /// A best effort canceled order may not have been removed on other dYdX + /// nodes including other dYdX validator nodes and may still be included in + /// future order matches. + BestEffortCanceled = 1, + /// A canceled order is one that is confirmed to be removed on all dYdX nodes + /// (discounting dishonest dYdX nodes) and will not be included in any future + /// order matches. + /// The cases where this happens includes: + /// - the order is expired. + Canceled = 2, + /// An order was fully-filled. Only sent by the Indexer for stateful orders. + Filled = 3, + } + impl OrderRemovalStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OrderRemovalStatus::Unspecified => "ORDER_REMOVAL_STATUS_UNSPECIFIED", + OrderRemovalStatus::BestEffortCanceled => { + "ORDER_REMOVAL_STATUS_BEST_EFFORT_CANCELED" + } + OrderRemovalStatus::Canceled => "ORDER_REMOVAL_STATUS_CANCELED", + OrderRemovalStatus::Filled => "ORDER_REMOVAL_STATUS_FILLED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ORDER_REMOVAL_STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "ORDER_REMOVAL_STATUS_BEST_EFFORT_CANCELED" => { + Some(Self::BestEffortCanceled) + } + "ORDER_REMOVAL_STATUS_CANCELED" => Some(Self::Canceled), + "ORDER_REMOVAL_STATUS_FILLED" => Some(Self::Filled), + _ => None, + } + } + } +} +impl ::prost::Name for OrderRemoveV1 { + const NAME: &'static str = "OrderRemoveV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.off_chain_updates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.off_chain_updates.OrderRemoveV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.off_chain_updates.OrderRemoveV1".into() + } +} +/// OrderUpdate messages contain the id of the order being updated, and the +/// updated total filled quantums of the order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderUpdateV1 { + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, + #[prost(uint64, tag = "2")] + pub total_filled_quantums: u64, +} +impl ::prost::Name for OrderUpdateV1 { + const NAME: &'static str = "OrderUpdateV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.off_chain_updates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.off_chain_updates.OrderUpdateV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.off_chain_updates.OrderUpdateV1".into() + } +} +/// OrderReplace messages contain the replacement order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderReplaceV1 { + #[prost(message, optional, tag = "1")] + pub order: ::core::option::Option, + #[prost(enumeration = "order_place_v1::OrderPlacementStatus", tag = "2")] + pub placement_status: i32, + #[prost(message, optional, tag = "3")] + pub time_stamp: ::core::option::Option<::prost_types::Timestamp>, +} +impl ::prost::Name for OrderReplaceV1 { + const NAME: &'static str = "OrderReplaceV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.off_chain_updates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.off_chain_updates.OrderReplaceV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.off_chain_updates.OrderReplaceV1".into() + } +} +/// An OffChainUpdate message is the message type which will be sent on Kafka to +/// the Indexer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OffChainUpdateV1 { + /// Contains one of an OrderPlaceV1, OrderRemoveV1, OrderUpdateV1, and + /// OrderReplaceV1 message. + #[prost(oneof = "off_chain_update_v1::UpdateMessage", tags = "1, 2, 3, 4")] + pub update_message: ::core::option::Option, +} +/// Nested message and enum types in `OffChainUpdateV1`. +pub mod off_chain_update_v1 { + /// Contains one of an OrderPlaceV1, OrderRemoveV1, OrderUpdateV1, and + /// OrderReplaceV1 message. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum UpdateMessage { + #[prost(message, tag = "1")] + OrderPlace(super::OrderPlaceV1), + #[prost(message, tag = "2")] + OrderRemove(super::OrderRemoveV1), + #[prost(message, tag = "3")] + OrderUpdate(super::OrderUpdateV1), + #[prost(message, tag = "4")] + OrderReplace(super::OrderReplaceV1), + } +} +impl ::prost::Name for OffChainUpdateV1 { + const NAME: &'static str = "OffChainUpdateV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.off_chain_updates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.off_chain_updates.OffChainUpdateV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.off_chain_updates.OffChainUpdateV1".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs b/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs new file mode 100644 index 0000000000..b25016f4af --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs @@ -0,0 +1,450 @@ +// This file is @generated by prost-build. +/// IndexerSubaccountId defines a unique identifier for a Subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerSubaccountId { + /// The address of the wallet that owns this subaccount. + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + /// < 128 Since 128 should be enough to start and it fits within + /// 1 Byte (1 Bit needed to indicate that the first byte is the last). + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for IndexerSubaccountId { + const NAME: &'static str = "IndexerSubaccountId"; + const PACKAGE: &'static str = "dydxprotocol.indexer.protocol.v1"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.protocol.v1.IndexerSubaccountId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.protocol.v1.IndexerSubaccountId".into() + } +} +/// IndexerPerpetualPosition are an account’s positions of a `Perpetual`. +/// Therefore they hold any information needed to trade perpetuals. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerPerpetualPosition { + /// The `Id` of the `Perpetual`. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The size of the position in base quantums. + #[prost(bytes = "vec", tag = "2")] + pub quantums: ::prost::alloc::vec::Vec, + /// The funding_index of the `Perpetual` the last time this position was + /// settled. + #[prost(bytes = "vec", tag = "3")] + pub funding_index: ::prost::alloc::vec::Vec, + /// Amount of funding payment (in quote quantums). + /// Note: 1. this field is not cumulative. + /// 2. a positive value means funding payment was paid out and + /// a negative value means funding payment was received. + #[prost(bytes = "vec", tag = "4")] + pub funding_payment: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for IndexerPerpetualPosition { + const NAME: &'static str = "IndexerPerpetualPosition"; + const PACKAGE: &'static str = "dydxprotocol.indexer.protocol.v1"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.protocol.v1.IndexerPerpetualPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.protocol.v1.IndexerPerpetualPosition".into() + } +} +/// IndexerAssetPosition define an account’s positions of an `Asset`. +/// Therefore they hold any information needed to trade on Spot and Margin. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerAssetPosition { + /// The `Id` of the `Asset`. + #[prost(uint32, tag = "1")] + pub asset_id: u32, + /// The absolute size of the position in base quantums. + #[prost(bytes = "vec", tag = "2")] + pub quantums: ::prost::alloc::vec::Vec, + /// The `Index` (either `LongIndex` or `ShortIndex`) of the `Asset` the last + /// time this position was settled + /// TODO(DEC-582): pending margin trading being added. + #[prost(uint64, tag = "3")] + pub index: u64, +} +impl ::prost::Name for IndexerAssetPosition { + const NAME: &'static str = "IndexerAssetPosition"; + const PACKAGE: &'static str = "dydxprotocol.indexer.protocol.v1"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.protocol.v1.IndexerAssetPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.protocol.v1.IndexerAssetPosition".into() + } +} +/// IndexerOrderId refers to a single order belonging to a Subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerOrderId { + /// The subaccount ID that opened this order. + /// Note that this field has `gogoproto.nullable = false` so that it is + /// generated as a value instead of a pointer. This is because the `OrderId` + /// proto is used as a key within maps, and map comparisons will compare + /// pointers for equality (when the desired behavior is to compare the values). + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// The client ID of this order, unique with respect to the specific + /// sub account (I.E., the same subaccount can't have two orders with + /// the same ClientId). + #[prost(fixed32, tag = "2")] + pub client_id: u32, + /// order_flags represent order flags for the order. This field is invalid if + /// it's greater than 127 (larger than one byte). Each bit in the first byte + /// represents a different flag. Currently only two flags are supported. + /// + /// Starting from the bit after the most MSB (note that the MSB is used in + /// proto varint encoding, and therefore cannot be used): Bit 1 is set if this + /// order is a Long-Term order (0x40, or 64 as a uint8). Bit 2 is set if this + /// order is a Conditional order (0x20, or 32 as a uint8). + /// + /// If neither bit is set, the order is assumed to be a Short-Term order. + /// + /// If both bits are set or bits other than the 2nd and 3rd are set, the order + /// ID is invalid. + #[prost(uint32, tag = "3")] + pub order_flags: u32, + /// ID of the CLOB the order is created for. + #[prost(uint32, tag = "4")] + pub clob_pair_id: u32, +} +impl ::prost::Name for IndexerOrderId { + const NAME: &'static str = "IndexerOrderId"; + const PACKAGE: &'static str = "dydxprotocol.indexer.protocol.v1"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.protocol.v1.IndexerOrderId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.protocol.v1.IndexerOrderId".into() + } +} +/// IndexerOrderV1 represents a single order belonging to a `Subaccount` +/// for a particular `ClobPair`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerOrder { + /// The unique ID of this order. Meant to be unique across all orders. + #[prost(message, optional, tag = "1")] + pub order_id: ::core::option::Option, + #[prost(enumeration = "indexer_order::Side", tag = "2")] + pub side: i32, + /// The size of this order in base quantums. Must be a multiple of + /// `ClobPair.StepBaseQuantums` (where `ClobPair.Id = orderId.ClobPairId`). + #[prost(uint64, tag = "3")] + pub quantums: u64, + /// The price level that this order will be placed at on the orderbook, + /// in subticks. Must be a multiple of ClobPair.SubticksPerTick + /// (where `ClobPair.Id = orderId.ClobPairId`). + #[prost(uint64, tag = "4")] + pub subticks: u64, + /// The time in force of this order. + #[prost(enumeration = "indexer_order::TimeInForce", tag = "7")] + pub time_in_force: i32, + /// Enforces that the order can only reduce the size of an existing position. + /// If a ReduceOnly order would change the side of the existing position, + /// its size is reduced to that of the remaining size of the position. + /// If existing orders on the book with ReduceOnly + /// would already close the position, the least aggressive (out-of-the-money) + /// ReduceOnly orders are resized and canceled first. + #[prost(bool, tag = "8")] + pub reduce_only: bool, + /// Set of bit flags set arbitrarily by clients and ignored by the protocol. + /// Used by indexer to infer information about a placed order. + #[prost(uint32, tag = "9")] + pub client_metadata: u32, + #[prost(enumeration = "indexer_order::ConditionType", tag = "10")] + pub condition_type: i32, + /// conditional_order_trigger_subticks represents the price at which this order + /// will be triggered. If the condition_type is CONDITION_TYPE_UNSPECIFIED, + /// this value is enforced to be 0. If this value is nonzero, condition_type + /// cannot be CONDITION_TYPE_UNSPECIFIED. Value is in subticks. + /// Must be a multiple of ClobPair.SubticksPerTick (where `ClobPair.Id = + /// orderId.ClobPairId`). + #[prost(uint64, tag = "11")] + pub conditional_order_trigger_subticks: u64, + /// Information about when the order expires. + #[prost(oneof = "indexer_order::GoodTilOneof", tags = "5, 6")] + pub good_til_oneof: ::core::option::Option, +} +/// Nested message and enum types in `IndexerOrder`. +pub mod indexer_order { + /// Represents the side of the orderbook the order will be placed on. + /// Note that Side.SIDE_UNSPECIFIED is an invalid order and cannot be + /// placed on the orderbook. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Side { + /// Default value. This value is invalid and unused. + Unspecified = 0, + /// SIDE_BUY is used to represent a BUY order. + Buy = 1, + /// SIDE_SELL is used to represent a SELL order. + Sell = 2, + } + impl Side { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Side::Unspecified => "SIDE_UNSPECIFIED", + Side::Buy => "SIDE_BUY", + Side::Sell => "SIDE_SELL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SIDE_UNSPECIFIED" => Some(Self::Unspecified), + "SIDE_BUY" => Some(Self::Buy), + "SIDE_SELL" => Some(Self::Sell), + _ => None, + } + } + } + /// TimeInForce indicates how long an order will remain active before it + /// is executed or expires. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum TimeInForce { + /// TIME_IN_FORCE_UNSPECIFIED represents the default behavior where an + /// order will first match with existing orders on the book, and any + /// remaining size will be added to the book as a maker order. + Unspecified = 0, + /// TIME_IN_FORCE_IOC enforces that an order only be matched with + /// maker orders on the book. If the order has remaining size after + /// matching with existing orders on the book, the remaining size + /// is not placed on the book. + Ioc = 1, + /// TIME_IN_FORCE_POST_ONLY enforces that an order only be placed + /// on the book as a maker order. Note this means that validators will cancel + /// any newly-placed post only orders that would cross with other maker + /// orders. + PostOnly = 2, + /// TIME_IN_FORCE_FILL_OR_KILL enforces that an order will either be filled + /// completely and immediately by maker orders on the book or canceled if the + /// entire amount can‘t be matched. + FillOrKill = 3, + } + impl TimeInForce { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + TimeInForce::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", + TimeInForce::Ioc => "TIME_IN_FORCE_IOC", + TimeInForce::PostOnly => "TIME_IN_FORCE_POST_ONLY", + TimeInForce::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TIME_IN_FORCE_UNSPECIFIED" => Some(Self::Unspecified), + "TIME_IN_FORCE_IOC" => Some(Self::Ioc), + "TIME_IN_FORCE_POST_ONLY" => Some(Self::PostOnly), + "TIME_IN_FORCE_FILL_OR_KILL" => Some(Self::FillOrKill), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ConditionType { + /// CONDITION_TYPE_UNSPECIFIED represents the default behavior where an + /// order will be placed immediately on the orderbook. + Unspecified = 0, + /// CONDITION_TYPE_STOP_LOSS represents a stop order. A stop order will + /// trigger when the oracle price moves at or above the trigger price for + /// buys, and at or below the trigger price for sells. + StopLoss = 1, + /// CONDITION_TYPE_TAKE_PROFIT represents a take profit order. A take profit + /// order will trigger when the oracle price moves at or below the trigger + /// price for buys and at or above the trigger price for sells. + TakeProfit = 2, + } + impl ConditionType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ConditionType::Unspecified => "CONDITION_TYPE_UNSPECIFIED", + ConditionType::StopLoss => "CONDITION_TYPE_STOP_LOSS", + ConditionType::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CONDITION_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "CONDITION_TYPE_STOP_LOSS" => Some(Self::StopLoss), + "CONDITION_TYPE_TAKE_PROFIT" => Some(Self::TakeProfit), + _ => None, + } + } + } + /// Information about when the order expires. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum GoodTilOneof { + /// The last block this order can be executed at (after which it will be + /// unfillable). Used only for Short-Term orders. If this value is non-zero + /// then the order is assumed to be a Short-Term order. + #[prost(uint32, tag = "5")] + GoodTilBlock(u32), + /// good_til_block_time represents the unix timestamp (in seconds) at which a + /// stateful order will be considered expired. The + /// good_til_block_time is always evaluated against the previous block's + /// `BlockTime` instead of the block in which the order is committed. If this + /// value is non-zero then the order is assumed to be a stateful or + /// conditional order. + #[prost(fixed32, tag = "6")] + GoodTilBlockTime(u32), + } +} +impl ::prost::Name for IndexerOrder { + const NAME: &'static str = "IndexerOrder"; + const PACKAGE: &'static str = "dydxprotocol.indexer.protocol.v1"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.protocol.v1.IndexerOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.protocol.v1.IndexerOrder".into() + } +} +/// Status of the CLOB. +/// Defined in clob.clob_pair +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ClobPairStatus { + /// Default value. This value is invalid and unused. + Unspecified = 0, + /// CLOB_PAIR_STATUS_ACTIVE behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + Active = 1, + /// CLOB_PAIR_STATUS_PAUSED behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + Paused = 2, + /// CLOB_PAIR_STATUS_CANCEL_ONLY behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + CancelOnly = 3, + /// CLOB_PAIR_STATUS_POST_ONLY behavior is unfinalized. + /// TODO(DEC-600): update this documentation. + PostOnly = 4, + /// CLOB_PAIR_STATUS_INITIALIZING represents a newly-added clob pair. + /// Clob pairs in this state only accept orders which are + /// both short-term and post-only. + Initializing = 5, + /// CLOB_PAIR_STATUS_FINAL_SETTLEMENT represents a clob pair that has been + /// deactivated. Clob pairs in this state do not accept new orders and trading + /// is blocked. All open positions are closed and open stateful orders canceled + /// by the protocol when the clob pair transitions to this status. All + /// short-term orders are left to expire. + FinalSettlement = 6, +} +impl ClobPairStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ClobPairStatus::Unspecified => "CLOB_PAIR_STATUS_UNSPECIFIED", + ClobPairStatus::Active => "CLOB_PAIR_STATUS_ACTIVE", + ClobPairStatus::Paused => "CLOB_PAIR_STATUS_PAUSED", + ClobPairStatus::CancelOnly => "CLOB_PAIR_STATUS_CANCEL_ONLY", + ClobPairStatus::PostOnly => "CLOB_PAIR_STATUS_POST_ONLY", + ClobPairStatus::Initializing => "CLOB_PAIR_STATUS_INITIALIZING", + ClobPairStatus::FinalSettlement => "CLOB_PAIR_STATUS_FINAL_SETTLEMENT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CLOB_PAIR_STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "CLOB_PAIR_STATUS_ACTIVE" => Some(Self::Active), + "CLOB_PAIR_STATUS_PAUSED" => Some(Self::Paused), + "CLOB_PAIR_STATUS_CANCEL_ONLY" => Some(Self::CancelOnly), + "CLOB_PAIR_STATUS_POST_ONLY" => Some(Self::PostOnly), + "CLOB_PAIR_STATUS_INITIALIZING" => Some(Self::Initializing), + "CLOB_PAIR_STATUS_FINAL_SETTLEMENT" => Some(Self::FinalSettlement), + _ => None, + } + } +} +/// Market type of perpetual. +/// Defined in perpetual. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PerpetualMarketType { + /// Unspecified market type. + Unspecified = 0, + /// Market type for cross margin perpetual markets. + Cross = 1, + /// Market type for isolated margin perpetual markets. + Isolated = 2, +} +impl PerpetualMarketType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PerpetualMarketType::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", + PerpetualMarketType::Cross => "PERPETUAL_MARKET_TYPE_CROSS", + PerpetualMarketType::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PERPETUAL_MARKET_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "PERPETUAL_MARKET_TYPE_CROSS" => Some(Self::Cross), + "PERPETUAL_MARKET_TYPE_ISOLATED" => Some(Self::Isolated), + _ => None, + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.redis.rs b/v4-proto-rs/src/dydxprotocol.indexer.redis.rs new file mode 100644 index 0000000000..bdb1bdccc3 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.redis.rs @@ -0,0 +1,83 @@ +// This file is @generated by prost-build. +/// RedisOrder is a proto for orders stored in Redis. This proto holds some +/// human-readable values such as price, size and ticker as well as the original +/// `Order` proto from the dYdX application. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RedisOrder { + /// uuid of the Order generated by the Indexer based on the `OrderId`. + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + /// Order proto from the protocol. + #[prost(message, optional, tag = "2")] + pub order: ::core::option::Option, + /// Ticker for the exchange pair for the order. + #[prost(string, tag = "3")] + pub ticker: ::prost::alloc::string::String, + /// Type of the ticker, PERPETUAL or SPOT. + #[prost(enumeration = "redis_order::TickerType", tag = "4")] + pub ticker_type: i32, + /// Human-readable price of the order. + #[prost(string, tag = "5")] + pub price: ::prost::alloc::string::String, + /// Human-readable size of the order. + #[prost(string, tag = "6")] + pub size: ::prost::alloc::string::String, +} +/// Nested message and enum types in `RedisOrder`. +pub mod redis_order { + /// Enum for the ticker type, PERPETUAL or SPOT. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum TickerType { + /// Default value for the enum. Should never be used in an initialized + /// `RedisOrder`. + Unspecified = 0, + /// Ticker is for a perpetual pair. + Perpetual = 1, + /// Ticker is for a spot pair. + Spot = 2, + } + impl TickerType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + TickerType::Unspecified => "TICKER_TYPE_UNSPECIFIED", + TickerType::Perpetual => "TICKER_TYPE_PERPETUAL", + TickerType::Spot => "TICKER_TYPE_SPOT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TICKER_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "TICKER_TYPE_PERPETUAL" => Some(Self::Perpetual), + "TICKER_TYPE_SPOT" => Some(Self::Spot), + _ => None, + } + } + } +} +impl ::prost::Name for RedisOrder { + const NAME: &'static str = "RedisOrder"; + const PACKAGE: &'static str = "dydxprotocol.indexer.redis"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.redis.RedisOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.redis.RedisOrder".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.shared.rs b/v4-proto-rs/src/dydxprotocol.indexer.shared.rs new file mode 100644 index 0000000000..570398f54b --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.shared.rs @@ -0,0 +1,125 @@ +// This file is @generated by prost-build. +/// OrderRemovalReason is an enum of all the reasons an order was removed. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum OrderRemovalReason { + /// Default value, this is invalid and unused. + Unspecified = 0, + /// The order was removed due to being expired. + Expired = 1, + /// The order was removed due to being canceled by a user. + UserCanceled = 2, + /// The order was removed due to being undercollateralized. + Undercollateralized = 3, + /// The order caused an internal error during order placement and was + /// removed. + InternalError = 4, + /// The order would have matched against another order placed by the same + /// subaccount and was removed. + SelfTradeError = 5, + /// The order would have matched against maker orders on the orderbook + /// despite being a post-only order and was removed. + PostOnlyWouldCrossMakerOrder = 6, + /// The order was an ICO order and would have been placed on the orderbook as + /// resting liquidity and was removed. + ImmediateOrCancelWouldRestOnBook = 7, + /// The order was a fill-or-kill order that could not be fully filled and was + /// removed. + FokOrderCouldNotBeFullyFulled = 8, + /// The order was a reduce-only order that was removed due to either: + /// - being a taker order and fully-filling the order would flip the side of + /// the subaccount's position, in this case the remaining size of the + /// order is removed + /// - being a maker order resting on the book and being removed when either + /// the subaccount's position is closed or flipped sides + ReduceOnlyResize = 9, + /// The order should be expired, according to the Indexer's cached data, but + /// the Indexer has yet to receive a message to remove the order. In order to + /// keep the data cached by the Indexer up-to-date and accurate, clear out + /// the data if it's expired by sending an order removal with this reason. + /// Protocol should never send this reason to Indexer. + IndexerExpired = 10, + /// The order has been replaced. + Replaced = 11, + /// The order has been fully-filled. Only sent by the Indexer for stateful + /// orders. + FullyFilled = 12, + /// The order has been removed since the subaccount does not satisfy the + /// equity tier requirements. + EquityTier = 13, + /// The order has been removed since its ClobPair has entered final settlement. + FinalSettlement = 14, + /// The order has been removed since filling it would lead to the subaccount + /// violating isolated subaccount constraints. + ViolatesIsolatedSubaccountConstraints = 15, +} +impl OrderRemovalReason { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OrderRemovalReason::Unspecified => "ORDER_REMOVAL_REASON_UNSPECIFIED", + OrderRemovalReason::Expired => "ORDER_REMOVAL_REASON_EXPIRED", + OrderRemovalReason::UserCanceled => "ORDER_REMOVAL_REASON_USER_CANCELED", + OrderRemovalReason::Undercollateralized => { + "ORDER_REMOVAL_REASON_UNDERCOLLATERALIZED" + } + OrderRemovalReason::InternalError => "ORDER_REMOVAL_REASON_INTERNAL_ERROR", + OrderRemovalReason::SelfTradeError => "ORDER_REMOVAL_REASON_SELF_TRADE_ERROR", + OrderRemovalReason::PostOnlyWouldCrossMakerOrder => { + "ORDER_REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" + } + OrderRemovalReason::ImmediateOrCancelWouldRestOnBook => { + "ORDER_REMOVAL_REASON_IMMEDIATE_OR_CANCEL_WOULD_REST_ON_BOOK" + } + OrderRemovalReason::FokOrderCouldNotBeFullyFulled => { + "ORDER_REMOVAL_REASON_FOK_ORDER_COULD_NOT_BE_FULLY_FULLED" + } + OrderRemovalReason::ReduceOnlyResize => { + "ORDER_REMOVAL_REASON_REDUCE_ONLY_RESIZE" + } + OrderRemovalReason::IndexerExpired => "ORDER_REMOVAL_REASON_INDEXER_EXPIRED", + OrderRemovalReason::Replaced => "ORDER_REMOVAL_REASON_REPLACED", + OrderRemovalReason::FullyFilled => "ORDER_REMOVAL_REASON_FULLY_FILLED", + OrderRemovalReason::EquityTier => "ORDER_REMOVAL_REASON_EQUITY_TIER", + OrderRemovalReason::FinalSettlement => { + "ORDER_REMOVAL_REASON_FINAL_SETTLEMENT" + } + OrderRemovalReason::ViolatesIsolatedSubaccountConstraints => { + "ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" + } + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ORDER_REMOVAL_REASON_UNSPECIFIED" => Some(Self::Unspecified), + "ORDER_REMOVAL_REASON_EXPIRED" => Some(Self::Expired), + "ORDER_REMOVAL_REASON_USER_CANCELED" => Some(Self::UserCanceled), + "ORDER_REMOVAL_REASON_UNDERCOLLATERALIZED" => Some(Self::Undercollateralized), + "ORDER_REMOVAL_REASON_INTERNAL_ERROR" => Some(Self::InternalError), + "ORDER_REMOVAL_REASON_SELF_TRADE_ERROR" => Some(Self::SelfTradeError), + "ORDER_REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" => { + Some(Self::PostOnlyWouldCrossMakerOrder) + } + "ORDER_REMOVAL_REASON_IMMEDIATE_OR_CANCEL_WOULD_REST_ON_BOOK" => { + Some(Self::ImmediateOrCancelWouldRestOnBook) + } + "ORDER_REMOVAL_REASON_FOK_ORDER_COULD_NOT_BE_FULLY_FULLED" => { + Some(Self::FokOrderCouldNotBeFullyFulled) + } + "ORDER_REMOVAL_REASON_REDUCE_ONLY_RESIZE" => Some(Self::ReduceOnlyResize), + "ORDER_REMOVAL_REASON_INDEXER_EXPIRED" => Some(Self::IndexerExpired), + "ORDER_REMOVAL_REASON_REPLACED" => Some(Self::Replaced), + "ORDER_REMOVAL_REASON_FULLY_FILLED" => Some(Self::FullyFilled), + "ORDER_REMOVAL_REASON_EQUITY_TIER" => Some(Self::EquityTier), + "ORDER_REMOVAL_REASON_FINAL_SETTLEMENT" => Some(Self::FinalSettlement), + "ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" => { + Some(Self::ViolatesIsolatedSubaccountConstraints) + } + _ => None, + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.socks.rs b/v4-proto-rs/src/dydxprotocol.indexer.socks.rs new file mode 100644 index 0000000000..b664937294 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.indexer.socks.rs @@ -0,0 +1,196 @@ +// This file is @generated by prost-build. +/// Message to be sent through the 'to-websockets-orderbooks` kafka topic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OrderbookMessage { + /// Stringified JSON object of all events to be streamed. + #[prost(string, tag = "1")] + pub contents: ::prost::alloc::string::String, + /// Clob pair id of the Orderbook message. + #[prost(string, tag = "2")] + pub clob_pair_id: ::prost::alloc::string::String, + /// Version of the websocket message. + #[prost(string, tag = "3")] + pub version: ::prost::alloc::string::String, +} +impl ::prost::Name for OrderbookMessage { + const NAME: &'static str = "OrderbookMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.OrderbookMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.OrderbookMessage".into() + } +} +/// Message to be sent through the 'to-websockets-subaccounts` kafka topic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountMessage { + /// Block height where the contents occur. + #[prost(string, tag = "1")] + pub block_height: ::prost::alloc::string::String, + /// Transaction index where the contents occur. + #[prost(int32, tag = "2")] + pub transaction_index: i32, + /// Event index where the contents occur. + #[prost(uint32, tag = "3")] + pub event_index: u32, + /// Stringified JSON object of all events to be streamed. + #[prost(string, tag = "4")] + pub contents: ::prost::alloc::string::String, + /// Subaccount id that the content corresponds to. + #[prost(message, optional, tag = "5")] + pub subaccount_id: ::core::option::Option, + /// Version of the websocket message. + #[prost(string, tag = "6")] + pub version: ::prost::alloc::string::String, +} +impl ::prost::Name for SubaccountMessage { + const NAME: &'static str = "SubaccountMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.SubaccountMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.SubaccountMessage".into() + } +} +/// Message to be sent through the 'to-websockets-trades` kafka topic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TradeMessage { + /// Block height where the contents occur. + #[prost(string, tag = "1")] + pub block_height: ::prost::alloc::string::String, + /// Stringified JSON object of all events to be streamed. + #[prost(string, tag = "4")] + pub contents: ::prost::alloc::string::String, + /// Clob pair id of the Trade message. + #[prost(string, tag = "5")] + pub clob_pair_id: ::prost::alloc::string::String, + /// Version of the websocket message. + #[prost(string, tag = "6")] + pub version: ::prost::alloc::string::String, +} +impl ::prost::Name for TradeMessage { + const NAME: &'static str = "TradeMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.TradeMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.TradeMessage".into() + } +} +/// Message to be sent through the 'to-websockets-markets` kafka topic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketMessage { + /// Stringified JSON object of all events to be streamed. + #[prost(string, tag = "1")] + pub contents: ::prost::alloc::string::String, + /// Version of the websocket message. + #[prost(string, tag = "2")] + pub version: ::prost::alloc::string::String, +} +impl ::prost::Name for MarketMessage { + const NAME: &'static str = "MarketMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.MarketMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.MarketMessage".into() + } +} +/// Message to be sent through the 'to-websockets-candles` kafka topic. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CandleMessage { + /// Stringified JSON object of all events to be streamed. + #[prost(string, tag = "1")] + pub contents: ::prost::alloc::string::String, + /// Clob pair id of the Candle message. + #[prost(string, tag = "2")] + pub clob_pair_id: ::prost::alloc::string::String, + /// Resolution of the candle update. + #[prost(enumeration = "candle_message::Resolution", tag = "3")] + pub resolution: i32, + /// Version of the websocket message. + #[prost(string, tag = "4")] + pub version: ::prost::alloc::string::String, +} +/// Nested message and enum types in `CandleMessage`. +pub mod candle_message { + /// TODO(IND-210): Make this proto conform and update downstream indexer logic + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Resolution { + /// buf:lint:ignore ENUM_VALUE_PREFIX + /// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX + OneMinute = 0, + /// buf:lint:ignore ENUM_VALUE_PREFIX + FiveMinutes = 1, + /// buf:lint:ignore ENUM_VALUE_PREFIX + FifteenMinutes = 2, + /// buf:lint:ignore ENUM_VALUE_PREFIX + ThirtyMinutes = 3, + /// buf:lint:ignore ENUM_VALUE_PREFIX + OneHour = 4, + /// buf:lint:ignore ENUM_VALUE_PREFIX + FourHours = 5, + /// buf:lint:ignore ENUM_VALUE_PREFIX + OneDay = 6, + } + impl Resolution { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Resolution::OneMinute => "ONE_MINUTE", + Resolution::FiveMinutes => "FIVE_MINUTES", + Resolution::FifteenMinutes => "FIFTEEN_MINUTES", + Resolution::ThirtyMinutes => "THIRTY_MINUTES", + Resolution::OneHour => "ONE_HOUR", + Resolution::FourHours => "FOUR_HOURS", + Resolution::OneDay => "ONE_DAY", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ONE_MINUTE" => Some(Self::OneMinute), + "FIVE_MINUTES" => Some(Self::FiveMinutes), + "FIFTEEN_MINUTES" => Some(Self::FifteenMinutes), + "THIRTY_MINUTES" => Some(Self::ThirtyMinutes), + "ONE_HOUR" => Some(Self::OneHour), + "FOUR_HOURS" => Some(Self::FourHours), + "ONE_DAY" => Some(Self::OneDay), + _ => None, + } + } + } +} +impl ::prost::Name for CandleMessage { + const NAME: &'static str = "CandleMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.CandleMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.CandleMessage".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.perpetuals.rs b/v4-proto-rs/src/dydxprotocol.perpetuals.rs new file mode 100644 index 0000000000..7fd52a2abb --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.perpetuals.rs @@ -0,0 +1,1152 @@ +// This file is @generated by prost-build. +/// Perpetual represents a perpetual on the dYdX exchange. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Perpetual { + /// PerpetualParams is the parameters of the perpetual. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, + /// The current index determined by the cumulative all-time + /// history of the funding mechanism. Starts at zero. + #[prost(bytes = "vec", tag = "2")] + pub funding_index: ::prost::alloc::vec::Vec, + /// Total size of open long contracts, measured in base_quantums. + #[prost(bytes = "vec", tag = "3")] + pub open_interest: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for Perpetual { + const NAME: &'static str = "Perpetual"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.Perpetual".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.Perpetual".into() + } +} +/// PerpetualParams represents the parameters of a perpetual on the dYdX +/// exchange. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualParams { + /// Unique, sequentially-generated. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The name of the `Perpetual` (e.g. `BTC-USD`). + #[prost(string, tag = "2")] + pub ticker: ::prost::alloc::string::String, + /// The market associated with this `Perpetual`. It + /// acts as the oracle price for the purposes of calculating + /// collateral, margin requirements, and funding rates. + #[prost(uint32, tag = "3")] + pub market_id: u32, + /// The exponent for converting an atomic amount (`size = 1`) + /// to a full coin. For example, if `AtomicResolution = -8` + /// then a `PerpetualPosition` with `size = 1e8` is equivalent to + /// a position size of one full coin. + #[prost(sint32, tag = "4")] + pub atomic_resolution: i32, + /// The default funding payment if there is no price premium. In + /// parts-per-million. + #[prost(sint32, tag = "5")] + pub default_funding_ppm: i32, + /// The liquidity_tier that this perpetual is associated with. + #[prost(uint32, tag = "6")] + pub liquidity_tier: u32, + /// The market type specifying if this perpetual is cross or isolated + #[prost(enumeration = "PerpetualMarketType", tag = "7")] + pub market_type: i32, +} +impl ::prost::Name for PerpetualParams { + const NAME: &'static str = "PerpetualParams"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.PerpetualParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.PerpetualParams".into() + } +} +/// MarketPremiums stores a list of premiums for a single perpetual market. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketPremiums { + /// perpetual_id is the Id of the perpetual market. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// premiums is a list of premium values for a perpetual market. Since most + /// premiums are zeros under "stable" market conditions, only non-zero values + /// are stored in this list. + #[prost(sint32, repeated, tag = "2")] + pub premiums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MarketPremiums { + const NAME: &'static str = "MarketPremiums"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MarketPremiums".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MarketPremiums".into() + } +} +/// PremiumStore is a struct to store a perpetual premiums for all +/// perpetual markets. It stores a list of `MarketPremiums`, each of which +/// corresponds to a perpetual market and stores a list of non-zero premium +/// values for that market. +/// This struct can either be used to store `PremiumVotes` or +/// `PremiumSamples`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PremiumStore { + /// all_market_premiums a list of `MarketPremiums`, each corresponding to + /// a perpetual market. + #[prost(message, repeated, tag = "1")] + pub all_market_premiums: ::prost::alloc::vec::Vec, + /// number of rounds where premium values were added. This value indicates + /// the total number of premiums (zeros and non-zeros) for each + /// `MarketPremiums` struct. Note that in the edge case a perpetual market was + /// added in the middle of a epoch, we don't keep a seperate count for that + /// market. This means we treat this market as having zero premiums before it + /// was added. + #[prost(uint32, tag = "2")] + pub num_premiums: u32, +} +impl ::prost::Name for PremiumStore { + const NAME: &'static str = "PremiumStore"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.PremiumStore".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.PremiumStore".into() + } +} +/// LiquidityTier stores margin information. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LiquidityTier { + /// Unique id. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The name of the tier purely for mnemonic purposes, e.g. "Gold". + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + /// The margin fraction needed to open a position. + /// In parts-per-million. + #[prost(uint32, tag = "3")] + pub initial_margin_ppm: u32, + /// The fraction of the initial-margin that the maintenance-margin is, + /// e.g. 50%. In parts-per-million. + #[prost(uint32, tag = "4")] + pub maintenance_fraction_ppm: u32, + /// The maximum position size at which the margin requirements are + /// not increased over the default values. Above this position size, + /// the margin requirements increase at a rate of sqrt(size). + /// + /// Deprecated since v3.x. + #[deprecated] + #[prost(uint64, tag = "5")] + pub base_position_notional: u64, + /// The impact notional amount (in quote quantums) is used to determine impact + /// bid/ask prices and its recommended value is 500 USDC / initial margin + /// fraction. + /// - Impact bid price = average execution price for a market sell of the + /// impact notional value. + /// - Impact ask price = average execution price for a market buy of the + /// impact notional value. + #[prost(uint64, tag = "6")] + pub impact_notional: u64, + /// Lower cap for Open Interest Margin Fracton (OIMF), in quote quantums. + /// IMF is not affected when OI <= open_interest_lower_cap. + #[prost(uint64, tag = "7")] + pub open_interest_lower_cap: u64, + /// Upper cap for Open Interest Margin Fracton (OIMF), in quote quantums. + /// IMF scales linearly to 100% as OI approaches open_interest_upper_cap. + /// If zero, then the IMF does not scale with OI. + #[prost(uint64, tag = "8")] + pub open_interest_upper_cap: u64, +} +impl ::prost::Name for LiquidityTier { + const NAME: &'static str = "LiquidityTier"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.LiquidityTier".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.LiquidityTier".into() + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PerpetualMarketType { + /// Unspecified market type. + Unspecified = 0, + /// Market type for cross margin perpetual markets. + Cross = 1, + /// Market type for isolated margin perpetual markets. + Isolated = 2, +} +impl PerpetualMarketType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PerpetualMarketType::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", + PerpetualMarketType::Cross => "PERPETUAL_MARKET_TYPE_CROSS", + PerpetualMarketType::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PERPETUAL_MARKET_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "PERPETUAL_MARKET_TYPE_CROSS" => Some(Self::Cross), + "PERPETUAL_MARKET_TYPE_ISOLATED" => Some(Self::Isolated), + _ => None, + } + } +} +/// Params defines the parameters for x/perpetuals module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Params { + /// Funding rate clamp factor in parts-per-million, used for clamping 8-hour + /// funding rates according to equation: |R| <= funding_rate_clamp_factor * + /// (initial margin - maintenance margin). + #[prost(uint32, tag = "1")] + pub funding_rate_clamp_factor_ppm: u32, + /// Premium vote clamp factor in parts-per-million, used for clamping premium + /// votes according to equation: |V| <= premium_vote_clamp_factor * + /// (initial margin - maintenance margin). + #[prost(uint32, tag = "2")] + pub premium_vote_clamp_factor_ppm: u32, + /// Minimum number of premium votes per premium sample. If number of premium + /// votes is smaller than this number, pad with zeros up to this number. + #[prost(uint32, tag = "3")] + pub min_num_votes_per_sample: u32, +} +impl ::prost::Name for Params { + const NAME: &'static str = "Params"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.Params".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.Params".into() + } +} +/// GenesisState defines the perpetuals module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub perpetuals: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub liquidity_tiers: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.GenesisState".into() + } +} +/// Queries a Perpetual by id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPerpetualRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryPerpetualRequest { + const NAME: &'static str = "QueryPerpetualRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPerpetualRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPerpetualRequest".into() + } +} +/// QueryPerpetualResponse is response type for the Perpetual RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPerpetualResponse { + #[prost(message, optional, tag = "1")] + pub perpetual: ::core::option::Option, +} +impl ::prost::Name for QueryPerpetualResponse { + const NAME: &'static str = "QueryPerpetualResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPerpetualResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPerpetualResponse".into() + } +} +/// Queries a list of Perpetual items. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllPerpetualsRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllPerpetualsRequest { + const NAME: &'static str = "QueryAllPerpetualsRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryAllPerpetualsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryAllPerpetualsRequest".into() + } +} +/// QueryAllPerpetualsResponse is response type for the AllPerpetuals RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllPerpetualsResponse { + #[prost(message, repeated, tag = "1")] + pub perpetual: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllPerpetualsResponse { + const NAME: &'static str = "QueryAllPerpetualsResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryAllPerpetualsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryAllPerpetualsResponse".into() + } +} +/// Queries a list of LiquidityTier items. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllLiquidityTiersRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllLiquidityTiersRequest { + const NAME: &'static str = "QueryAllLiquidityTiersRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryAllLiquidityTiersRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryAllLiquidityTiersRequest".into() + } +} +/// QueryAllLiquidityTiersResponse is response type for the AllLiquidityTiers RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllLiquidityTiersResponse { + #[prost(message, repeated, tag = "1")] + pub liquidity_tiers: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllLiquidityTiersResponse { + const NAME: &'static str = "QueryAllLiquidityTiersResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryAllLiquidityTiersResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryAllLiquidityTiersResponse".into() + } +} +/// QueryPremiumVotesRequest is the request type for the PremiumVotes RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPremiumVotesRequest {} +impl ::prost::Name for QueryPremiumVotesRequest { + const NAME: &'static str = "QueryPremiumVotesRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPremiumVotesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPremiumVotesRequest".into() + } +} +/// QueryPremiumVotesResponse is the response type for the PremiumVotes RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPremiumVotesResponse { + #[prost(message, optional, tag = "1")] + pub premium_votes: ::core::option::Option, +} +impl ::prost::Name for QueryPremiumVotesResponse { + const NAME: &'static str = "QueryPremiumVotesResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPremiumVotesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPremiumVotesResponse".into() + } +} +/// QueryPremiumSamplesRequest is the request type for the PremiumSamples RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPremiumSamplesRequest {} +impl ::prost::Name for QueryPremiumSamplesRequest { + const NAME: &'static str = "QueryPremiumSamplesRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPremiumSamplesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPremiumSamplesRequest".into() + } +} +/// QueryPremiumSamplesResponse is the response type for the PremiumSamples RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPremiumSamplesResponse { + #[prost(message, optional, tag = "1")] + pub premium_samples: ::core::option::Option, +} +impl ::prost::Name for QueryPremiumSamplesResponse { + const NAME: &'static str = "QueryPremiumSamplesResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryPremiumSamplesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryPremiumSamplesResponse".into() + } +} +/// QueryParamsResponse is the response type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsRequest {} +impl ::prost::Name for QueryParamsRequest { + const NAME: &'static str = "QueryParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryParamsRequest".into() + } +} +/// QueryParamsResponse is the response type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryParamsResponse { + const NAME: &'static str = "QueryParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.QueryParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.QueryParamsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a Perpetual by id. + pub async fn perpetual( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/Perpetual", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.perpetuals.Query", "Perpetual")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of Perpetual items. + pub async fn all_perpetuals( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/AllPerpetuals", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Query", "AllPerpetuals"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries a list of LiquidityTiers. + pub async fn all_liquidity_tiers( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/AllLiquidityTiers", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Query", "AllLiquidityTiers"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries a list of premium votes. + pub async fn premium_votes( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/PremiumVotes", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Query", "PremiumVotes"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries a list of premium samples. + pub async fn premium_samples( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/PremiumSamples", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Query", "PremiumSamples"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the perpetual params. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.perpetuals.Query", "Params")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgCreatePerpetual is a message used by x/gov to create a new perpetual. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreatePerpetual { + /// The address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// `params` defines parameters for the new perpetual market. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgCreatePerpetual { + const NAME: &'static str = "MsgCreatePerpetual"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgCreatePerpetual".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgCreatePerpetual".into() + } +} +/// MsgCreatePerpetualResponse defines the CreatePerpetual +/// response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreatePerpetualResponse {} +impl ::prost::Name for MsgCreatePerpetualResponse { + const NAME: &'static str = "MsgCreatePerpetualResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgCreatePerpetualResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgCreatePerpetualResponse".into() + } +} +/// MsgSetLiquidityTier is a message used by x/gov to create or update a +/// liquidity tier. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetLiquidityTier { + /// The address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The liquidity tier to create or update. + #[prost(message, optional, tag = "2")] + pub liquidity_tier: ::core::option::Option, +} +impl ::prost::Name for MsgSetLiquidityTier { + const NAME: &'static str = "MsgSetLiquidityTier"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgSetLiquidityTier".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgSetLiquidityTier".into() + } +} +/// MsgSetLiquidityTierResponse defines the SetLiquidityTier response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetLiquidityTierResponse {} +impl ::prost::Name for MsgSetLiquidityTierResponse { + const NAME: &'static str = "MsgSetLiquidityTierResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgSetLiquidityTierResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgSetLiquidityTierResponse".into() + } +} +/// MsgUpdatePerpetualParams is a message used by x/gov to update the parameters +/// of a perpetual. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdatePerpetualParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The perpetual to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub perpetual_params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdatePerpetualParams { + const NAME: &'static str = "MsgUpdatePerpetualParams"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgUpdatePerpetualParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgUpdatePerpetualParams".into() + } +} +/// MsgUpdatePerpetualParamsResponse defines the UpdatePerpetualParams +/// response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdatePerpetualParamsResponse {} +impl ::prost::Name for MsgUpdatePerpetualParamsResponse { + const NAME: &'static str = "MsgUpdatePerpetualParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgUpdatePerpetualParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgUpdatePerpetualParamsResponse".into() + } +} +/// FundingPremium represents a funding premium value for a perpetual +/// market. Can be used to represent a premium vote or a premium sample. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FundingPremium { + /// The id of the perpetual market. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The sampled premium rate. In parts-per-million. + #[prost(int32, tag = "2")] + pub premium_ppm: i32, +} +impl ::prost::Name for FundingPremium { + const NAME: &'static str = "FundingPremium"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.FundingPremium".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.FundingPremium".into() + } +} +/// MsgAddPremiumVotes is a request type for the AddPremiumVotes method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAddPremiumVotes { + #[prost(message, repeated, tag = "1")] + pub votes: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgAddPremiumVotes { + const NAME: &'static str = "MsgAddPremiumVotes"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgAddPremiumVotes".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgAddPremiumVotes".into() + } +} +/// MsgAddPremiumVotesResponse defines the AddPremiumVotes +/// response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAddPremiumVotesResponse {} +impl ::prost::Name for MsgAddPremiumVotesResponse { + const NAME: &'static str = "MsgAddPremiumVotesResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgAddPremiumVotesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgAddPremiumVotesResponse".into() + } +} +/// MsgUpdateParams is a message used by x/gov to update the parameters of the +/// perpetuals module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateParams { + const NAME: &'static str = "MsgUpdateParams"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgUpdateParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgUpdateParams".into() + } +} +/// MsgUpdateParamsResponse defines the UpdateParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParamsResponse {} +impl ::prost::Name for MsgUpdateParamsResponse { + const NAME: &'static str = "MsgUpdateParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.perpetuals"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.perpetuals.MsgUpdateParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.perpetuals.MsgUpdateParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// AddPremiumVotes add new samples of the funding premiums to the + /// application. + pub async fn add_premium_votes( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Msg/AddPremiumVotes", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Msg", "AddPremiumVotes"), + ); + self.inner.unary(req, path, codec).await + } + /// CreatePerpetual creates a new perpetual object. + pub async fn create_perpetual( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Msg/CreatePerpetual", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Msg", "CreatePerpetual"), + ); + self.inner.unary(req, path, codec).await + } + /// SetLiquidityTier creates an liquidity tier if the ID doesn't exist, and + /// updates the existing liquidity tier otherwise. + pub async fn set_liquidity_tier( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Msg/SetLiquidityTier", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.perpetuals.Msg", "SetLiquidityTier"), + ); + self.inner.unary(req, path, codec).await + } + /// UpdatePerpetualParams updates the parameters of a perpetual market. + pub async fn update_perpetual_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Msg/UpdatePerpetualParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.perpetuals.Msg", + "UpdatePerpetualParams", + ), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateParams updates the parameters of perpetuals module. + pub async fn update_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.perpetuals.Msg/UpdateParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.perpetuals.Msg", "UpdateParams")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.prices.rs b/v4-proto-rs/src/dydxprotocol.prices.rs new file mode 100644 index 0000000000..a62d3cf018 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.prices.rs @@ -0,0 +1,737 @@ +// This file is @generated by prost-build. +/// MarketParam represents the x/prices configuration for markets, including +/// representing price values, resolving markets on individual exchanges, and +/// generating price updates. This configuration is specific to the quote +/// currency. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketParam { + /// Unique, sequentially-generated value. + #[prost(uint32, tag = "1")] + pub id: u32, + /// The human-readable name of the market pair (e.g. `BTC-USD`). + #[prost(string, tag = "2")] + pub pair: ::prost::alloc::string::String, + /// Static value. The exponent of the price. + /// For example if `Exponent == -5` then a `Value` of `1,000,000,000` + /// represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest + /// price step (in dollars) that can be recorded. + #[prost(sint32, tag = "3")] + pub exponent: i32, + /// The minimum number of exchanges that should be reporting a live price for + /// a price update to be considered valid. + #[prost(uint32, tag = "4")] + pub min_exchanges: u32, + /// The minimum allowable change in `price` value that would cause a price + /// update on the network. Measured as `1e-6` (parts per million). + #[prost(uint32, tag = "5")] + pub min_price_change_ppm: u32, + /// A string of json that encodes the configuration for resolving the price + /// of this market on various exchanges. + #[prost(string, tag = "6")] + pub exchange_config_json: ::prost::alloc::string::String, +} +impl ::prost::Name for MarketParam { + const NAME: &'static str = "MarketParam"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MarketParam".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MarketParam".into() + } +} +/// MarketPrice is used by the application to store/retrieve oracle price. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketPrice { + /// Unique, sequentially-generated value that matches `MarketParam`. + #[prost(uint32, tag = "1")] + pub id: u32, + /// Static value. The exponent of the price. See the comment on the duplicate + /// MarketParam field for more information. + #[prost(sint32, tag = "2")] + pub exponent: i32, + /// The variable value that is updated by oracle price updates. `0` if it has + /// never been updated, `>0` otherwise. + #[prost(uint64, tag = "3")] + pub price: u64, +} +impl ::prost::Name for MarketPrice { + const NAME: &'static str = "MarketPrice"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MarketPrice".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MarketPrice".into() + } +} +/// GenesisState defines the prices module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub market_params: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub market_prices: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.GenesisState".into() + } +} +/// QueryMarketPriceRequest is request type for the Query/Params `MarketPrice` +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMarketPriceRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryMarketPriceRequest { + const NAME: &'static str = "QueryMarketPriceRequest"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryMarketPriceRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryMarketPriceRequest".into() + } +} +/// QueryMarketPriceResponse is response type for the Query/Params `MarketPrice` +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMarketPriceResponse { + #[prost(message, optional, tag = "1")] + pub market_price: ::core::option::Option, +} +impl ::prost::Name for QueryMarketPriceResponse { + const NAME: &'static str = "QueryMarketPriceResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryMarketPriceResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryMarketPriceResponse".into() + } +} +/// QueryAllMarketPricesRequest is request type for the Query/Params +/// `AllMarketPrices` RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllMarketPricesRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllMarketPricesRequest { + const NAME: &'static str = "QueryAllMarketPricesRequest"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryAllMarketPricesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryAllMarketPricesRequest".into() + } +} +/// QueryAllMarketPricesResponse is response type for the Query/Params +/// `AllMarketPrices` RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllMarketPricesResponse { + #[prost(message, repeated, tag = "1")] + pub market_prices: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllMarketPricesResponse { + const NAME: &'static str = "QueryAllMarketPricesResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryAllMarketPricesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryAllMarketPricesResponse".into() + } +} +/// QueryMarketParamsRequest is request type for the Query/Params `MarketParams` +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMarketParamRequest { + #[prost(uint32, tag = "1")] + pub id: u32, +} +impl ::prost::Name for QueryMarketParamRequest { + const NAME: &'static str = "QueryMarketParamRequest"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryMarketParamRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryMarketParamRequest".into() + } +} +/// QueryMarketParamResponse is response type for the Query/Params `MarketParams` +/// RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMarketParamResponse { + #[prost(message, optional, tag = "1")] + pub market_param: ::core::option::Option, +} +impl ::prost::Name for QueryMarketParamResponse { + const NAME: &'static str = "QueryMarketParamResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryMarketParamResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryMarketParamResponse".into() + } +} +/// QueryAllMarketParamsRequest is request type for the Query/Params +/// `AllMarketParams` RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllMarketParamsRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllMarketParamsRequest { + const NAME: &'static str = "QueryAllMarketParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryAllMarketParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryAllMarketParamsRequest".into() + } +} +/// QueryAllMarketParamsResponse is response type for the Query/Params +/// `AllMarketParams` RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllMarketParamsResponse { + #[prost(message, repeated, tag = "1")] + pub market_params: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllMarketParamsResponse { + const NAME: &'static str = "QueryAllMarketParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.QueryAllMarketParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.QueryAllMarketParamsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a MarketPrice by id. + pub async fn market_price( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Query/MarketPrice", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.prices.Query", "MarketPrice")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of MarketPrice items. + pub async fn all_market_prices( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Query/AllMarketPrices", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.prices.Query", "AllMarketPrices")); + self.inner.unary(req, path, codec).await + } + /// Queries a MarketParam by id. + pub async fn market_param( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Query/MarketParam", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.prices.Query", "MarketParam")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of MarketParam items. + pub async fn all_market_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Query/AllMarketParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.prices.Query", "AllMarketParams")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgCreateOracleMarket is a message used by x/gov for creating a new oracle +/// market. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateOracleMarket { + /// The address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// `params` defines parameters for the new oracle market. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgCreateOracleMarket { + const NAME: &'static str = "MsgCreateOracleMarket"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgCreateOracleMarket".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgCreateOracleMarket".into() + } +} +/// MsgCreateOracleMarketResponse defines the CreateOracleMarket response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateOracleMarketResponse {} +impl ::prost::Name for MsgCreateOracleMarketResponse { + const NAME: &'static str = "MsgCreateOracleMarketResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgCreateOracleMarketResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgCreateOracleMarketResponse".into() + } +} +/// MsgUpdateMarketPrices is a request type for the UpdateMarketPrices method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateMarketPrices { + #[prost(message, repeated, tag = "1")] + pub market_price_updates: ::prost::alloc::vec::Vec< + msg_update_market_prices::MarketPrice, + >, +} +/// Nested message and enum types in `MsgUpdateMarketPrices`. +pub mod msg_update_market_prices { + /// MarketPrice represents a price update for a single market + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MarketPrice { + /// The id of market to update + #[prost(uint32, tag = "1")] + pub market_id: u32, + /// The updated price + #[prost(uint64, tag = "2")] + pub price: u64, + } + impl ::prost::Name for MarketPrice { + const NAME: &'static str = "MarketPrice"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgUpdateMarketPrices.MarketPrice".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgUpdateMarketPrices.MarketPrice".into() + } + } +} +impl ::prost::Name for MsgUpdateMarketPrices { + const NAME: &'static str = "MsgUpdateMarketPrices"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgUpdateMarketPrices".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgUpdateMarketPrices".into() + } +} +/// MsgUpdateMarketPricesResponse defines the MsgUpdateMarketPrices response +/// type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateMarketPricesResponse {} +impl ::prost::Name for MsgUpdateMarketPricesResponse { + const NAME: &'static str = "MsgUpdateMarketPricesResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgUpdateMarketPricesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgUpdateMarketPricesResponse".into() + } +} +/// MsgUpdateMarketParam is a message used by x/gov for updating the parameters +/// of an oracle market. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateMarketParam { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The market param to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub market_param: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateMarketParam { + const NAME: &'static str = "MsgUpdateMarketParam"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgUpdateMarketParam".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgUpdateMarketParam".into() + } +} +/// MsgUpdateMarketParamResponse defines the UpdateMarketParam response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateMarketParamResponse {} +impl ::prost::Name for MsgUpdateMarketParamResponse { + const NAME: &'static str = "MsgUpdateMarketParamResponse"; + const PACKAGE: &'static str = "dydxprotocol.prices"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.prices.MsgUpdateMarketParamResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.prices.MsgUpdateMarketParamResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// UpdateMarketPrices updates the oracle price of a market relative to + /// quoteCurrency. + pub async fn update_market_prices( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Msg/UpdateMarketPrices", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.prices.Msg", "UpdateMarketPrices"), + ); + self.inner.unary(req, path, codec).await + } + /// CreateOracleMarket creates a new oracle market. + pub async fn create_oracle_market( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Msg/CreateOracleMarket", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.prices.Msg", "CreateOracleMarket"), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateMarketParams allows governance to update the parameters of an + /// oracle market. + pub async fn update_market_param( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.prices.Msg/UpdateMarketParam", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.prices.Msg", "UpdateMarketParam")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.ratelimit.rs b/v4-proto-rs/src/dydxprotocol.ratelimit.rs new file mode 100644 index 0000000000..d243ba3c70 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.ratelimit.rs @@ -0,0 +1,557 @@ +// This file is @generated by prost-build. +/// LimitParams defines rate limit params on a denom. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LimitParams { + /// denom is the denomination of the token being rate limited. + /// e.g. ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5 + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + /// limiters is a list of rate-limiters on this denom. All limiters + /// must be satified for a withdrawal to proceed. + #[prost(message, repeated, tag = "2")] + pub limiters: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for LimitParams { + const NAME: &'static str = "LimitParams"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.LimitParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.LimitParams".into() + } +} +/// Limiter defines one rate-limiter on a specfic denom. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Limiter { + /// period is the rolling time period for which the limit applies + /// e.g. 3600 (an hour) + #[prost(message, optional, tag = "1")] + pub period: ::core::option::Option<::prost_types::Duration>, + /// baseline_minimum is the minimum maximum withdrawal coin amount within the + /// time period. + /// e.g. 100_000_000_000 uusdc for 100k USDC; 5e22 adv4tnt for 50k DV4TNT + #[prost(bytes = "vec", tag = "3")] + pub baseline_minimum: ::prost::alloc::vec::Vec, + /// baseline_tvl_ppm is the maximum ratio of TVL withdrawable in + /// the time period, in part-per-million. + /// e.g. 100_000 (10%) + #[prost(uint32, tag = "4")] + pub baseline_tvl_ppm: u32, +} +impl ::prost::Name for Limiter { + const NAME: &'static str = "Limiter"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.Limiter".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.Limiter".into() + } +} +/// DenomCapacity stores a list of rate limit capacity for a denom. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DenomCapacity { + /// denom is the denomination of the token being rate limited. + /// e.g. ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5 + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + /// capacity_list is a list of capacity amount tracked for each `Limiter` + /// on the denom. This list has a 1:1 mapping to `limiter` list under + /// `LimitParams`. + #[prost(bytes = "vec", repeated, tag = "2")] + pub capacity_list: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +impl ::prost::Name for DenomCapacity { + const NAME: &'static str = "DenomCapacity"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.DenomCapacity".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.DenomCapacity".into() + } +} +/// LimiterCapacity contains a pair of limiter and its corresponding capacity. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LimiterCapacity { + #[prost(message, optional, tag = "1")] + pub limiter: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub capacity: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for LimiterCapacity { + const NAME: &'static str = "LimiterCapacity"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.LimiterCapacity".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.LimiterCapacity".into() + } +} +/// GenesisState defines the ratelimit module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// limit_params_list defines the list of `LimitParams` at genesis. + #[prost(message, repeated, tag = "1")] + pub limit_params_list: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.GenesisState".into() + } +} +/// PendingSendPacket contains the channel_id and sequence pair to identify a +/// pending packet +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PendingSendPacket { + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub sequence: u64, +} +impl ::prost::Name for PendingSendPacket { + const NAME: &'static str = "PendingSendPacket"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.PendingSendPacket".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.PendingSendPacket".into() + } +} +/// ListLimitParamsRequest is a request type of the ListLimitParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListLimitParamsRequest {} +impl ::prost::Name for ListLimitParamsRequest { + const NAME: &'static str = "ListLimitParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.ListLimitParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.ListLimitParamsRequest".into() + } +} +/// ListLimitParamsResponse is a response type of the ListLimitParams RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListLimitParamsResponse { + #[prost(message, repeated, tag = "1")] + pub limit_params_list: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for ListLimitParamsResponse { + const NAME: &'static str = "ListLimitParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.ListLimitParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.ListLimitParamsResponse".into() + } +} +/// QueryCapacityByDenomRequest is a request type for the CapacityByDenom RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCapacityByDenomRequest { + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryCapacityByDenomRequest { + const NAME: &'static str = "QueryCapacityByDenomRequest"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.QueryCapacityByDenomRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.QueryCapacityByDenomRequest".into() + } +} +/// QueryCapacityByDenomResponse is a response type of the CapacityByDenom RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCapacityByDenomResponse { + #[prost(message, repeated, tag = "1")] + pub limiter_capacity_list: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryCapacityByDenomResponse { + const NAME: &'static str = "QueryCapacityByDenomResponse"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.QueryCapacityByDenomResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.QueryCapacityByDenomResponse".into() + } +} +/// QueryAllPendingSendPacketsRequest is a request type for the +/// AllPendingSendPackets RPC +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllPendingSendPacketsRequest {} +impl ::prost::Name for QueryAllPendingSendPacketsRequest { + const NAME: &'static str = "QueryAllPendingSendPacketsRequest"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.QueryAllPendingSendPacketsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.QueryAllPendingSendPacketsRequest".into() + } +} +/// QueryAllPendingSendPacketsResponse is a response type of the +/// AllPendingSendPackets RPC +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllPendingSendPacketsResponse { + #[prost(message, repeated, tag = "1")] + pub pending_send_packets: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryAllPendingSendPacketsResponse { + const NAME: &'static str = "QueryAllPendingSendPacketsResponse"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.QueryAllPendingSendPacketsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.QueryAllPendingSendPacketsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// List all limit params. + pub async fn list_limit_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.ratelimit.Query/ListLimitParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.ratelimit.Query", "ListLimitParams"), + ); + self.inner.unary(req, path, codec).await + } + /// Query capacity by denom. + pub async fn capacity_by_denom( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.ratelimit.Query/CapacityByDenom", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.ratelimit.Query", "CapacityByDenom"), + ); + self.inner.unary(req, path, codec).await + } + /// Get all pending send packets + pub async fn all_pending_send_packets( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.ratelimit.Query/AllPendingSendPackets", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.ratelimit.Query", + "AllPendingSendPackets", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgSetLimitParams is the Msg/SetLimitParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetLimitParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Defines the parameters to set. All parameters must be supplied. + #[prost(message, optional, tag = "2")] + pub limit_params: ::core::option::Option, +} +impl ::prost::Name for MsgSetLimitParams { + const NAME: &'static str = "MsgSetLimitParams"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.MsgSetLimitParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.MsgSetLimitParams".into() + } +} +/// MsgSetLimitParamsResponse is the Msg/SetLimitParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetLimitParamsResponse {} +impl ::prost::Name for MsgSetLimitParamsResponse { + const NAME: &'static str = "MsgSetLimitParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.ratelimit"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.ratelimit.MsgSetLimitParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.ratelimit.MsgSetLimitParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SetLimitParams sets a `LimitParams` object in state. + pub async fn set_limit_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.ratelimit.Msg/SetLimitParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.ratelimit.Msg", "SetLimitParams")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.rewards.rs b/v4-proto-rs/src/dydxprotocol.rewards.rs new file mode 100644 index 0000000000..ec3a05e69f --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.rewards.rs @@ -0,0 +1,366 @@ +// This file is @generated by prost-build. +/// Params defines the parameters for x/rewards module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Params { + /// The module account to distribute rewards from. + #[prost(string, tag = "1")] + pub treasury_account: ::prost::alloc::string::String, + /// The denom of the rewards token. + #[prost(string, tag = "2")] + pub denom: ::prost::alloc::string::String, + /// The exponent of converting one unit of `denom` to a full coin. + /// For example, `denom=uatom, denom_exponent=-6` defines that + /// `1 uatom = 10^(-6) ATOM`. This conversion is needed since the + /// `market_id` retrieves the price of a full coin of the reward token. + #[prost(sint32, tag = "3")] + pub denom_exponent: i32, + /// The id of the market that has the price of the rewards token. + #[prost(uint32, tag = "4")] + pub market_id: u32, + /// The amount (in ppm) that fees are multiplied by to get + /// the maximum rewards amount. + #[prost(uint32, tag = "5")] + pub fee_multiplier_ppm: u32, +} +impl ::prost::Name for Params { + const NAME: &'static str = "Params"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.Params".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.Params".into() + } +} +/// GenesisState defines the rewards module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The parameters of the module. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.GenesisState".into() + } +} +/// QueryParamsRequest is a request type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsRequest {} +impl ::prost::Name for QueryParamsRequest { + const NAME: &'static str = "QueryParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.QueryParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.QueryParamsRequest".into() + } +} +/// QueryParamsResponse is a response type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryParamsResponse { + const NAME: &'static str = "QueryParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.QueryParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.QueryParamsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the Params. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.rewards.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.rewards.Query", "Params")); + self.inner.unary(req, path, codec).await + } + } +} +/// RewardShare stores the relative weight of rewards that each address is +/// entitled to. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RewardShare { + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub weight: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for RewardShare { + const NAME: &'static str = "RewardShare"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.RewardShare".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.RewardShare".into() + } +} +/// MsgUpdateParams is the Msg/UpdateParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateParams { + const NAME: &'static str = "MsgUpdateParams"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.MsgUpdateParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.MsgUpdateParams".into() + } +} +/// MsgUpdateParamsResponse is the Msg/UpdateParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParamsResponse {} +impl ::prost::Name for MsgUpdateParamsResponse { + const NAME: &'static str = "MsgUpdateParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.rewards"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.rewards.MsgUpdateParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.rewards.MsgUpdateParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// UpdateParams updates the Params in state. + pub async fn update_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.rewards.Msg/UpdateParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.rewards.Msg", "UpdateParams")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.sending.rs b/v4-proto-rs/src/dydxprotocol.sending.rs new file mode 100644 index 0000000000..7a3bb775b0 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.sending.rs @@ -0,0 +1,498 @@ +// This file is @generated by prost-build. +/// GenesisState defines the sending module's genesis state. +/// +/// this line is used by starport scaffolding # genesis/proto/state +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState {} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.GenesisState".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + } +} +/// Transfer represents a single transfer between two subaccounts. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfer { + /// The sender subaccount ID. + #[prost(message, optional, tag = "1")] + pub sender: ::core::option::Option, + /// The recipient subaccount ID. + #[prost(message, optional, tag = "2")] + pub recipient: ::core::option::Option, + /// Id of the asset to transfer. + #[prost(uint32, tag = "3")] + pub asset_id: u32, + /// The amount of asset to transfer + #[prost(uint64, tag = "4")] + pub amount: u64, +} +impl ::prost::Name for Transfer { + const NAME: &'static str = "Transfer"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.Transfer".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.Transfer".into() + } +} +/// MsgDepositToSubaccount represents a single transfer from an `x/bank` +/// account to an `x/subaccounts` subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToSubaccount { + /// The sender wallet address. + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + /// The recipient subaccount ID. + #[prost(message, optional, tag = "2")] + pub recipient: ::core::option::Option, + /// Id of the asset to transfer. + #[prost(uint32, tag = "3")] + pub asset_id: u32, + /// The number of quantums of asset to transfer. + #[prost(uint64, tag = "4")] + pub quantums: u64, +} +impl ::prost::Name for MsgDepositToSubaccount { + const NAME: &'static str = "MsgDepositToSubaccount"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgDepositToSubaccount".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgDepositToSubaccount".into() + } +} +/// MsgWithdrawFromSubaccount represents a single transfer from an +/// `x/subaccounts` subaccount to an `x/bank` account. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgWithdrawFromSubaccount { + /// The sender subaccount ID. + #[prost(message, optional, tag = "2")] + pub sender: ::core::option::Option, + /// The recipient wallet address. + #[prost(string, tag = "1")] + pub recipient: ::prost::alloc::string::String, + /// Id of the asset to transfer. + #[prost(uint32, tag = "3")] + pub asset_id: u32, + /// The number of quantums of asset to transfer. + #[prost(uint64, tag = "4")] + pub quantums: u64, +} +impl ::prost::Name for MsgWithdrawFromSubaccount { + const NAME: &'static str = "MsgWithdrawFromSubaccount"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgWithdrawFromSubaccount".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgWithdrawFromSubaccount".into() + } +} +/// MsgSendFromModuleToAccount represents a single transfer from a module +/// to an `x/bank` account (can be either a module account address or a user +/// account address). +/// Should only be executed by governance. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSendFromModuleToAccount { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The sender module name. + #[prost(string, tag = "2")] + pub sender_module_name: ::prost::alloc::string::String, + /// The recipient account address (can be either a module account address + /// or a user account address). + #[prost(string, tag = "3")] + pub recipient: ::prost::alloc::string::String, + /// The coin to transfer, which specifies both denom and amount. + #[prost(message, optional, tag = "4")] + pub coin: ::core::option::Option, +} +impl ::prost::Name for MsgSendFromModuleToAccount { + const NAME: &'static str = "MsgSendFromModuleToAccount"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgSendFromModuleToAccount".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgSendFromModuleToAccount".into() + } +} +/// MsgCreateTransfer is a request type used for initiating new transfers. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateTransfer { + #[prost(message, optional, tag = "1")] + pub transfer: ::core::option::Option, +} +impl ::prost::Name for MsgCreateTransfer { + const NAME: &'static str = "MsgCreateTransfer"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgCreateTransfer".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgCreateTransfer".into() + } +} +/// MsgCreateTransferResponse is a response type used for new transfers. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateTransferResponse {} +impl ::prost::Name for MsgCreateTransferResponse { + const NAME: &'static str = "MsgCreateTransferResponse"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgCreateTransferResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgCreateTransferResponse".into() + } +} +/// MsgDepositToSubaccountResponse is a response type used for new +/// account-to-subaccount transfers. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToSubaccountResponse {} +impl ::prost::Name for MsgDepositToSubaccountResponse { + const NAME: &'static str = "MsgDepositToSubaccountResponse"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgDepositToSubaccountResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgDepositToSubaccountResponse".into() + } +} +/// MsgWithdrawFromSubaccountResponse is a response type used for new +/// subaccount-to-account transfers. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgWithdrawFromSubaccountResponse {} +impl ::prost::Name for MsgWithdrawFromSubaccountResponse { + const NAME: &'static str = "MsgWithdrawFromSubaccountResponse"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgWithdrawFromSubaccountResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgWithdrawFromSubaccountResponse".into() + } +} +/// MsgSendFromModuleToAccountResponse is a response type used for new +/// module-to-account transfers. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSendFromModuleToAccountResponse {} +impl ::prost::Name for MsgSendFromModuleToAccountResponse { + const NAME: &'static str = "MsgSendFromModuleToAccountResponse"; + const PACKAGE: &'static str = "dydxprotocol.sending"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.sending.MsgSendFromModuleToAccountResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.sending.MsgSendFromModuleToAccountResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// CreateTransfer initiates a new transfer between subaccounts. + pub async fn create_transfer( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.sending.Msg/CreateTransfer", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.sending.Msg", "CreateTransfer")); + self.inner.unary(req, path, codec).await + } + /// DepositToSubaccount initiates a new transfer from an `x/bank` account + /// to an `x/subaccounts` subaccount. + pub async fn deposit_to_subaccount( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.sending.Msg/DepositToSubaccount", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.sending.Msg", "DepositToSubaccount"), + ); + self.inner.unary(req, path, codec).await + } + /// WithdrawFromSubaccount initiates a new transfer from an `x/subaccounts` + /// subaccount to an `x/bank` account. + pub async fn withdraw_from_subaccount( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.sending.Msg/WithdrawFromSubaccount", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.sending.Msg", "WithdrawFromSubaccount"), + ); + self.inner.unary(req, path, codec).await + } + /// SendFromModuleToAccount initiates a new transfer from a module to an + /// `x/bank` account (should only be executed by governance). + pub async fn send_from_module_to_account( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.sending.Msg/SendFromModuleToAccount", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.sending.Msg", + "SendFromModuleToAccount", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.stats.rs b/v4-proto-rs/src/dydxprotocol.stats.rs new file mode 100644 index 0000000000..68ec458964 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.stats.rs @@ -0,0 +1,651 @@ +// This file is @generated by prost-build. +/// Params defines the parameters for x/stats module. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Params { + /// The desired number of seconds in the look-back window. + #[prost(message, optional, tag = "1")] + pub window_duration: ::core::option::Option<::prost_types::Duration>, +} +impl ::prost::Name for Params { + const NAME: &'static str = "Params"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.Params".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.Params".into() + } +} +/// GenesisState defines the stats module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The parameters of the module. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.GenesisState".into() + } +} +/// BlockStats is used to store stats transiently within the scope of a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockStats { + /// The fills that occured on this block. + #[prost(message, repeated, tag = "1")] + pub fills: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `BlockStats`. +pub mod block_stats { + /// Fill records data about a fill on this block. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Fill { + /// Taker wallet address + #[prost(string, tag = "1")] + pub taker: ::prost::alloc::string::String, + /// Maker wallet address + #[prost(string, tag = "2")] + pub maker: ::prost::alloc::string::String, + /// Notional USDC filled in quantums + #[prost(uint64, tag = "3")] + pub notional: u64, + } + impl ::prost::Name for Fill { + const NAME: &'static str = "Fill"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.BlockStats.Fill".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.BlockStats.Fill".into() + } + } +} +impl ::prost::Name for BlockStats { + const NAME: &'static str = "BlockStats"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.BlockStats".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.BlockStats".into() + } +} +/// StatsMetadata stores metadata for the x/stats module +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatsMetadata { + /// The oldest epoch that is included in the stats. The next epoch to be + /// removed from the window. + #[prost(uint32, tag = "1")] + pub trailing_epoch: u32, +} +impl ::prost::Name for StatsMetadata { + const NAME: &'static str = "StatsMetadata"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.StatsMetadata".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.StatsMetadata".into() + } +} +/// EpochStats stores stats for a particular epoch +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EpochStats { + /// Epoch end time + #[prost(message, optional, tag = "1")] + pub epoch_end_time: ::core::option::Option<::prost_types::Timestamp>, + /// Stats for each user in this epoch. Sorted by user. + #[prost(message, repeated, tag = "2")] + pub stats: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `EpochStats`. +pub mod epoch_stats { + /// A user and its associated stats + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct UserWithStats { + #[prost(string, tag = "1")] + pub user: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub stats: ::core::option::Option, + } + impl ::prost::Name for UserWithStats { + const NAME: &'static str = "UserWithStats"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.EpochStats.UserWithStats".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.EpochStats.UserWithStats".into() + } + } +} +impl ::prost::Name for EpochStats { + const NAME: &'static str = "EpochStats"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.EpochStats".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.EpochStats".into() + } +} +/// GlobalStats stores global stats +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GlobalStats { + /// Notional USDC traded in quantums + #[prost(uint64, tag = "1")] + pub notional_traded: u64, +} +impl ::prost::Name for GlobalStats { + const NAME: &'static str = "GlobalStats"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.GlobalStats".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.GlobalStats".into() + } +} +/// UserStats stores stats for a User +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UserStats { + /// Taker USDC in quantums + #[prost(uint64, tag = "1")] + pub taker_notional: u64, + /// Maker USDC in quantums + #[prost(uint64, tag = "2")] + pub maker_notional: u64, +} +impl ::prost::Name for UserStats { + const NAME: &'static str = "UserStats"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.UserStats".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.UserStats".into() + } +} +/// QueryParamsRequest is a request type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsRequest {} +impl ::prost::Name for QueryParamsRequest { + const NAME: &'static str = "QueryParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryParamsRequest".into() + } +} +/// QueryParamsResponse is a response type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryParamsResponse { + const NAME: &'static str = "QueryParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryParamsResponse".into() + } +} +/// QueryStatsMetadataRequest is a request type for the StatsMetadata RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryStatsMetadataRequest {} +impl ::prost::Name for QueryStatsMetadataRequest { + const NAME: &'static str = "QueryStatsMetadataRequest"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryStatsMetadataRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryStatsMetadataRequest".into() + } +} +/// QueryStatsMetadataResponse is a response type for the StatsMetadata RPC +/// method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryStatsMetadataResponse { + #[prost(message, optional, tag = "1")] + pub metadata: ::core::option::Option, +} +impl ::prost::Name for QueryStatsMetadataResponse { + const NAME: &'static str = "QueryStatsMetadataResponse"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryStatsMetadataResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryStatsMetadataResponse".into() + } +} +/// QueryGlobalStatsRequest is a request type for the GlobalStats RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGlobalStatsRequest {} +impl ::prost::Name for QueryGlobalStatsRequest { + const NAME: &'static str = "QueryGlobalStatsRequest"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryGlobalStatsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryGlobalStatsRequest".into() + } +} +/// QueryGlobalStatsResponse is a response type for the GlobalStats RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGlobalStatsResponse { + #[prost(message, optional, tag = "1")] + pub stats: ::core::option::Option, +} +impl ::prost::Name for QueryGlobalStatsResponse { + const NAME: &'static str = "QueryGlobalStatsResponse"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryGlobalStatsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryGlobalStatsResponse".into() + } +} +/// QueryUserStatsRequest is a request type for the UserStats RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryUserStatsRequest { + #[prost(string, tag = "1")] + pub user: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryUserStatsRequest { + const NAME: &'static str = "QueryUserStatsRequest"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryUserStatsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryUserStatsRequest".into() + } +} +/// QueryUserStatsResponse is a request type for the UserStats RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryUserStatsResponse { + #[prost(message, optional, tag = "1")] + pub stats: ::core::option::Option, +} +impl ::prost::Name for QueryUserStatsResponse { + const NAME: &'static str = "QueryUserStatsResponse"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.QueryUserStatsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.QueryUserStatsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the Params. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.stats.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.stats.Query", "Params")); + self.inner.unary(req, path, codec).await + } + /// Queries StatsMetadata. + pub async fn stats_metadata( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.stats.Query/StatsMetadata", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.stats.Query", "StatsMetadata")); + self.inner.unary(req, path, codec).await + } + /// Queries GlobalStats. + pub async fn global_stats( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.stats.Query/GlobalStats", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.stats.Query", "GlobalStats")); + self.inner.unary(req, path, codec).await + } + /// Queries UserStats. + pub async fn user_stats( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.stats.Query/UserStats", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.stats.Query", "UserStats")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgUpdateParams is the Msg/UpdateParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateParams { + const NAME: &'static str = "MsgUpdateParams"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.MsgUpdateParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.MsgUpdateParams".into() + } +} +/// MsgUpdateParamsResponse is the Msg/UpdateParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParamsResponse {} +impl ::prost::Name for MsgUpdateParamsResponse { + const NAME: &'static str = "MsgUpdateParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.MsgUpdateParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.MsgUpdateParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// UpdateParams updates the Params in state. + pub async fn update_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.stats.Msg/UpdateParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.stats.Msg", "UpdateParams")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.subaccounts.rs b/v4-proto-rs/src/dydxprotocol.subaccounts.rs new file mode 100644 index 0000000000..f08f01ff77 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.subaccounts.rs @@ -0,0 +1,490 @@ +// This file is @generated by prost-build. +/// AssetPositions define an account’s positions of an `Asset`. +/// Therefore they hold any information needed to trade on Spot and Margin. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssetPosition { + /// The `Id` of the `Asset`. + #[prost(uint32, tag = "1")] + pub asset_id: u32, + /// The absolute size of the position in base quantums. + #[prost(bytes = "vec", tag = "2")] + pub quantums: ::prost::alloc::vec::Vec, + /// The `Index` (either `LongIndex` or `ShortIndex`) of the `Asset` the last + /// time this position was settled + /// TODO(DEC-582): pending margin trading being added. + #[prost(uint64, tag = "3")] + pub index: u64, +} +impl ::prost::Name for AssetPosition { + const NAME: &'static str = "AssetPosition"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.AssetPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.AssetPosition".into() + } +} +/// PerpetualPositions are an account’s positions of a `Perpetual`. +/// Therefore they hold any information needed to trade perpetuals. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerpetualPosition { + /// The `Id` of the `Perpetual`. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The size of the position in base quantums. + #[prost(bytes = "vec", tag = "2")] + pub quantums: ::prost::alloc::vec::Vec, + /// The funding_index of the `Perpetual` the last time this position was + /// settled. + #[prost(bytes = "vec", tag = "3")] + pub funding_index: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for PerpetualPosition { + const NAME: &'static str = "PerpetualPosition"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.PerpetualPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.PerpetualPosition".into() + } +} +/// SubaccountId defines a unique identifier for a Subaccount. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubaccountId { + /// The address of the wallet that owns this subaccount. + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + /// The unique number of this subaccount for the owner. + /// Currently limited to 128*1000 subaccounts per owner. + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for SubaccountId { + const NAME: &'static str = "SubaccountId"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.SubaccountId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.SubaccountId".into() + } +} +/// Subaccount defines a single sub-account for a given address. +/// Subaccounts are uniquely indexed by a subaccountNumber/owner pair. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Subaccount { + /// The Id of the Subaccount + #[prost(message, optional, tag = "1")] + pub id: ::core::option::Option, + /// All `AssetPosition`s associated with this subaccount. + /// Always sorted ascending by `asset_id`. + #[prost(message, repeated, tag = "2")] + pub asset_positions: ::prost::alloc::vec::Vec, + /// All `PerpetualPosition`s associated with this subaccount. + /// Always sorted ascending by `perpetual_id. + #[prost(message, repeated, tag = "3")] + pub perpetual_positions: ::prost::alloc::vec::Vec, + /// Set by the owner. If true, then margin trades can be made in this + /// subaccount. + #[prost(bool, tag = "4")] + pub margin_enabled: bool, +} +impl ::prost::Name for Subaccount { + const NAME: &'static str = "Subaccount"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.Subaccount".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.Subaccount".into() + } +} +/// GenesisState defines the subaccounts module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub subaccounts: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.GenesisState".into() + } +} +/// QueryGetSubaccountRequest is request type for the Query RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGetSubaccountRequest { + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for QueryGetSubaccountRequest { + const NAME: &'static str = "QueryGetSubaccountRequest"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryGetSubaccountRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryGetSubaccountRequest".into() + } +} +/// QuerySubaccountResponse is response type for the Query RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySubaccountResponse { + #[prost(message, optional, tag = "1")] + pub subaccount: ::core::option::Option, +} +impl ::prost::Name for QuerySubaccountResponse { + const NAME: &'static str = "QuerySubaccountResponse"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QuerySubaccountResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QuerySubaccountResponse".into() + } +} +/// QueryAllSubaccountRequest is request type for the Query RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllSubaccountRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllSubaccountRequest { + const NAME: &'static str = "QueryAllSubaccountRequest"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryAllSubaccountRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryAllSubaccountRequest".into() + } +} +/// QuerySubaccountAllResponse is response type for the Query RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySubaccountAllResponse { + #[prost(message, repeated, tag = "1")] + pub subaccount: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QuerySubaccountAllResponse { + const NAME: &'static str = "QuerySubaccountAllResponse"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QuerySubaccountAllResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QuerySubaccountAllResponse".into() + } +} +/// QueryGetWithdrawalAndTransfersBlockedInfoRequest is a request type for +/// fetching information about whether withdrawals and transfers are blocked for +/// a collateral pool associated with the passed in perpetual id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGetWithdrawalAndTransfersBlockedInfoRequest { + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, +} +impl ::prost::Name for QueryGetWithdrawalAndTransfersBlockedInfoRequest { + const NAME: &'static str = "QueryGetWithdrawalAndTransfersBlockedInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryGetWithdrawalAndTransfersBlockedInfoRequest" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryGetWithdrawalAndTransfersBlockedInfoRequest" + .into() + } +} +/// QueryGetWithdrawalAndTransfersBlockedInfoRequest is a response type for +/// fetching information about whether withdrawals and transfers are blocked. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryGetWithdrawalAndTransfersBlockedInfoResponse { + #[prost(uint32, tag = "1")] + pub negative_tnc_subaccount_seen_at_block: u32, + #[prost(uint32, tag = "2")] + pub chain_outage_seen_at_block: u32, + #[prost(uint32, tag = "3")] + pub withdrawals_and_transfers_unblocked_at_block: u32, +} +impl ::prost::Name for QueryGetWithdrawalAndTransfersBlockedInfoResponse { + const NAME: &'static str = "QueryGetWithdrawalAndTransfersBlockedInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryGetWithdrawalAndTransfersBlockedInfoResponse" + .into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryGetWithdrawalAndTransfersBlockedInfoResponse" + .into() + } +} +/// QueryCollateralPoolAddressRequest is the request type for fetching the +/// account address of the collateral pool associated with the passed in +/// perpetual id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCollateralPoolAddressRequest { + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, +} +impl ::prost::Name for QueryCollateralPoolAddressRequest { + const NAME: &'static str = "QueryCollateralPoolAddressRequest"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryCollateralPoolAddressRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryCollateralPoolAddressRequest".into() + } +} +/// QueryCollateralPoolAddressResponse is a response type for fetching the +/// account address of the collateral pool associated with the passed in +/// perpetual id. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCollateralPoolAddressResponse { + #[prost(string, tag = "1")] + pub collateral_pool_address: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryCollateralPoolAddressResponse { + const NAME: &'static str = "QueryCollateralPoolAddressResponse"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.QueryCollateralPoolAddressResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.QueryCollateralPoolAddressResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries a Subaccount by id + pub async fn subaccount( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.subaccounts.Query/Subaccount", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.subaccounts.Query", "Subaccount")); + self.inner.unary(req, path, codec).await + } + /// Queries a list of Subaccount items. + pub async fn subaccount_all( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.subaccounts.Query/SubaccountAll", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.subaccounts.Query", "SubaccountAll"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries information about whether withdrawal and transfers are blocked, and + /// if so which block they are re-enabled on. + pub async fn get_withdrawal_and_transfers_blocked_info( + &mut self, + request: impl tonic::IntoRequest< + super::QueryGetWithdrawalAndTransfersBlockedInfoRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.subaccounts.Query/GetWithdrawalAndTransfersBlockedInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.subaccounts.Query", + "GetWithdrawalAndTransfersBlockedInfo", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries the collateral pool account address for a perpetual id. + pub async fn collateral_pool_address( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.subaccounts.Query/CollateralPoolAddress", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.subaccounts.Query", + "CollateralPoolAddress", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.vault.rs b/v4-proto-rs/src/dydxprotocol.vault.rs new file mode 100644 index 0000000000..9cf8e3d256 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.vault.rs @@ -0,0 +1,711 @@ +// This file is @generated by prost-build. +/// Params stores `x/vault` parameters. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Params { + /// The number of layers of orders a vault places. For example if + /// `layers=2`, a vault places 2 asks and 2 bids. + #[prost(uint32, tag = "1")] + pub layers: u32, + /// The minimum base spread when a vault quotes around reservation price. + #[prost(uint32, tag = "2")] + pub spread_min_ppm: u32, + /// The buffer amount to add to min_price_change_ppm to arrive at `spread` + /// according to formula: + /// `spread = max(spread_min_ppm, min_price_change_ppm + spread_buffer_ppm)`. + #[prost(uint32, tag = "3")] + pub spread_buffer_ppm: u32, + /// The factor that determines how aggressive a vault skews its orders. + #[prost(uint32, tag = "4")] + pub skew_factor_ppm: u32, + /// The percentage of vault equity that each order is sized at. + #[prost(uint32, tag = "5")] + pub order_size_pct_ppm: u32, + /// The duration that a vault's orders are valid for. + #[prost(uint32, tag = "6")] + pub order_expiration_seconds: u32, + /// The number of quote quantums in quote asset that a vault with no perpetual + /// positions must have to activate, i.e. if a vault has no perpetual positions + /// and has strictly less than this amount of quote asset, it will not + /// activate. + #[prost(bytes = "vec", tag = "7")] + pub activation_threshold_quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for Params { + const NAME: &'static str = "Params"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.Params".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.Params".into() + } +} +/// GenesisState defines `x/vault`'s genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The parameters of the module. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.GenesisState".into() + } +} +/// VaultId uniquely identifies a vault by its type and number. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VaultId { + /// Type of the vault. + #[prost(enumeration = "VaultType", tag = "1")] + pub r#type: i32, + /// Unique ID of the vault within above type. + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for VaultId { + const NAME: &'static str = "VaultId"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.VaultId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.VaultId".into() + } +} +/// NumShares represents the number of shares in a vault. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NumShares { + /// Number of shares. + #[prost(bytes = "vec", tag = "2")] + pub num_shares: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for NumShares { + const NAME: &'static str = "NumShares"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.NumShares".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.NumShares".into() + } +} +/// VaultType represents different types of vaults. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VaultType { + /// Default value, invalid and unused. + Unspecified = 0, + /// Vault is associated with a CLOB pair. + Clob = 1, +} +impl VaultType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + VaultType::Unspecified => "VAULT_TYPE_UNSPECIFIED", + VaultType::Clob => "VAULT_TYPE_CLOB", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VAULT_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "VAULT_TYPE_CLOB" => Some(Self::Clob), + _ => None, + } + } +} +/// QueryParamsRequest is a request type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsRequest {} +impl ::prost::Name for QueryParamsRequest { + const NAME: &'static str = "QueryParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryParamsRequest".into() + } +} +/// QueryParamsResponse is a response type for the Params RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryParamsResponse { + const NAME: &'static str = "QueryParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryParamsResponse".into() + } +} +/// QueryVaultRequest is a request type for the Vault RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryVaultRequest { + #[prost(enumeration = "VaultType", tag = "1")] + pub r#type: i32, + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for QueryVaultRequest { + const NAME: &'static str = "QueryVaultRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryVaultRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryVaultRequest".into() + } +} +/// QueryVaultResponse is a response type for the Vault RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryVaultResponse { + #[prost(message, optional, tag = "1")] + pub vault_id: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub subaccount_id: ::core::option::Option, + #[prost(uint64, tag = "3")] + pub equity: u64, + #[prost(uint64, tag = "4")] + pub inventory: u64, + #[prost(uint64, tag = "5")] + pub total_shares: u64, +} +impl ::prost::Name for QueryVaultResponse { + const NAME: &'static str = "QueryVaultResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryVaultResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryVaultResponse".into() + } +} +/// QueryAllVaultsRequest is a request type for the AllVaults RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllVaultsRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryAllVaultsRequest { + const NAME: &'static str = "QueryAllVaultsRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryAllVaultsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryAllVaultsRequest".into() + } +} +/// QueryAllVaultsResponse is a response type for the AllVaults RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllVaultsResponse { + #[prost(message, repeated, tag = "1")] + pub vaults: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllVaultsResponse { + const NAME: &'static str = "QueryAllVaultsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryAllVaultsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryAllVaultsResponse".into() + } +} +/// QueryOwnerSharesRequest is a request type for the OwnerShares RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryOwnerSharesRequest { + #[prost(enumeration = "VaultType", tag = "1")] + pub r#type: i32, + #[prost(uint32, tag = "2")] + pub number: u32, + #[prost(message, optional, tag = "3")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryOwnerSharesRequest { + const NAME: &'static str = "QueryOwnerSharesRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryOwnerSharesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryOwnerSharesRequest".into() + } +} +/// OwnerShare is a type for owner shares in a vault. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OwnerShare { + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub shares: ::core::option::Option, +} +impl ::prost::Name for OwnerShare { + const NAME: &'static str = "OwnerShare"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.OwnerShare".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.OwnerShare".into() + } +} +/// QueryOwnerSharesResponse is a response type for the OwnerShares RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryOwnerSharesResponse { + #[prost(message, repeated, tag = "1")] + pub owner_shares: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryOwnerSharesResponse { + const NAME: &'static str = "QueryOwnerSharesResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryOwnerSharesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryOwnerSharesResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the Params. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Params")); + self.inner.unary(req, path, codec).await + } + /// Queries a Vault by type and number. + pub async fn vault( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/Vault", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Vault")); + self.inner.unary(req, path, codec).await + } + /// Queries all vaults. + pub async fn all_vaults( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/AllVaults", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "AllVaults")); + self.inner.unary(req, path, codec).await + } + /// Queries owner shares of a vault. + pub async fn owner_shares( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/OwnerShares", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "OwnerShares")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgDepositToVault is the Msg/DepositToVault request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToVault { + /// The vault to deposit into. + #[prost(message, optional, tag = "1")] + pub vault_id: ::core::option::Option, + /// The subaccount to deposit from. + #[prost(message, optional, tag = "2")] + pub subaccount_id: ::core::option::Option, + /// Number of quote quantums to deposit. + #[prost(bytes = "vec", tag = "3")] + pub quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgDepositToVault { + const NAME: &'static str = "MsgDepositToVault"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgDepositToVault".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgDepositToVault".into() + } +} +/// MsgDepositToVaultResponse is the Msg/DepositToVault response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToVaultResponse {} +impl ::prost::Name for MsgDepositToVaultResponse { + const NAME: &'static str = "MsgDepositToVaultResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgDepositToVaultResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgDepositToVaultResponse".into() + } +} +/// MsgUpdateParams is the Msg/UpdateParams request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateParams { + const NAME: &'static str = "MsgUpdateParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateParams".into() + } +} +/// MsgUpdateParamsResponse is the Msg/UpdateParams response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateParamsResponse {} +impl ::prost::Name for MsgUpdateParamsResponse { + const NAME: &'static str = "MsgUpdateParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// DepositToVault deposits funds into a vault. + pub async fn deposit_to_vault( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Msg/DepositToVault", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "DepositToVault")); + self.inner.unary(req, path, codec).await + } + /// UpdateParams updates the Params in state. + pub async fn update_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Msg/UpdateParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "UpdateParams")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.vest.rs b/v4-proto-rs/src/dydxprotocol.vest.rs new file mode 100644 index 0000000000..f875d24e7d --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.vest.rs @@ -0,0 +1,410 @@ +// This file is @generated by prost-build. +/// VestEntry specifies a Vester Account and the rate at which tokens are +/// dripped into the corresponding Treasury Account. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VestEntry { + /// The module account to vest tokens from. + /// This is also the key to this `VestEntry` in state. + #[prost(string, tag = "1")] + pub vester_account: ::prost::alloc::string::String, + /// The module account to vest tokens to. + #[prost(string, tag = "2")] + pub treasury_account: ::prost::alloc::string::String, + /// The denom of the token to vest. + #[prost(string, tag = "3")] + pub denom: ::prost::alloc::string::String, + /// The start time of vest. Before this time, no vest will occur. + #[prost(message, optional, tag = "4")] + pub start_time: ::core::option::Option<::prost_types::Timestamp>, + /// The end time of vest. At this target date, all funds should be in the + /// Treasury Account and none left in the Vester Account. + #[prost(message, optional, tag = "5")] + pub end_time: ::core::option::Option<::prost_types::Timestamp>, +} +impl ::prost::Name for VestEntry { + const NAME: &'static str = "VestEntry"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.VestEntry".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.VestEntry".into() + } +} +/// GenesisState defines the vest module's genesis state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The vest entries at genesis. + #[prost(message, repeated, tag = "1")] + pub vest_entries: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.GenesisState".into() + } +} +/// QueryVestEntryRequest is a request type for the VestEntry RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryVestEntryRequest { + #[prost(string, tag = "1")] + pub vester_account: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryVestEntryRequest { + const NAME: &'static str = "QueryVestEntryRequest"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.QueryVestEntryRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.QueryVestEntryRequest".into() + } +} +/// QueryVestEntryResponse is a response type for the VestEntry RPC method. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryVestEntryResponse { + #[prost(message, optional, tag = "1")] + pub entry: ::core::option::Option, +} +impl ::prost::Name for QueryVestEntryResponse { + const NAME: &'static str = "QueryVestEntryResponse"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.QueryVestEntryResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.QueryVestEntryResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the VestEntry. + pub async fn vest_entry( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vest.Query/VestEntry", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vest.Query", "VestEntry")); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgDeleteVestEntry is the Msg/DeleteVestEntry request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDeleteVestEntry { + /// authority is the address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vester account of the vest entry to delete. + #[prost(string, tag = "2")] + pub vester_account: ::prost::alloc::string::String, +} +impl ::prost::Name for MsgDeleteVestEntry { + const NAME: &'static str = "MsgDeleteVestEntry"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.MsgDeleteVestEntry".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.MsgDeleteVestEntry".into() + } +} +/// MsgDeleteVestEntryResponse is the Msg/DeleteVestEntry response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDeleteVestEntryResponse {} +impl ::prost::Name for MsgDeleteVestEntryResponse { + const NAME: &'static str = "MsgDeleteVestEntryResponse"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.MsgDeleteVestEntryResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.MsgDeleteVestEntryResponse".into() + } +} +/// MsgSetVestEntry is the Msg/SetVestEntry request type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetVestEntry { + /// authority is the address that controls the module. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vest entry to set. + #[prost(message, optional, tag = "2")] + pub entry: ::core::option::Option, +} +impl ::prost::Name for MsgSetVestEntry { + const NAME: &'static str = "MsgSetVestEntry"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.MsgSetVestEntry".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.MsgSetVestEntry".into() + } +} +/// MsgSetVestEntryResponse is the Msg/SetVestEntry response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetVestEntryResponse {} +impl ::prost::Name for MsgSetVestEntryResponse { + const NAME: &'static str = "MsgSetVestEntryResponse"; + const PACKAGE: &'static str = "dydxprotocol.vest"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vest.MsgSetVestEntryResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vest.MsgSetVestEntryResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SetVestEntry sets a VestEntry in state. + pub async fn set_vest_entry( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vest.Msg/SetVestEntry", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vest.Msg", "SetVestEntry")); + self.inner.unary(req, path, codec).await + } + /// DeleteVestEntry deletes a VestEntry from state. + pub async fn delete_vest_entry( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vest.Msg/DeleteVestEntry", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vest.Msg", "DeleteVestEntry")); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/google.api.rs b/v4-proto-rs/src/google.api.rs new file mode 100644 index 0000000000..08318f49cf --- /dev/null +++ b/v4-proto-rs/src/google.api.rs @@ -0,0 +1,402 @@ +// This file is @generated by prost-build. +/// Defines the HTTP configuration for an API service. It contains a list of +/// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +/// to one or more HTTP REST API methods. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Http { + /// A list of HTTP configuration rules that apply to individual API methods. + /// + /// **NOTE:** All service configuration rules follow "last one wins" order. + #[prost(message, repeated, tag = "1")] + pub rules: ::prost::alloc::vec::Vec, + /// When set to true, URL path parameters will be fully URI-decoded except in + /// cases of single segment matches in reserved expansion, where "%2F" will be + /// left encoded. + /// + /// The default behavior is to not decode RFC 6570 reserved characters in multi + /// segment matches. + #[prost(bool, tag = "2")] + pub fully_decode_reserved_expansion: bool, +} +impl ::prost::Name for Http { + const NAME: &'static str = "Http"; + const PACKAGE: &'static str = "google.api"; + fn full_name() -> ::prost::alloc::string::String { + "google.api.Http".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/google.api.Http".into() + } +} +/// # gRPC Transcoding +/// +/// gRPC Transcoding is a feature for mapping between a gRPC method and one or +/// more HTTP REST endpoints. It allows developers to build a single API service +/// that supports both gRPC APIs and REST APIs. Many systems, including [Google +/// APIs](), +/// [Cloud Endpoints](), [gRPC +/// Gateway](), +/// and [Envoy]() proxy support this feature +/// and use it for large scale production services. +/// +/// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +/// how different portions of the gRPC request message are mapped to the URL +/// path, URL query parameters, and HTTP request body. It also controls how the +/// gRPC response message is mapped to the HTTP response body. `HttpRule` is +/// typically specified as an `google.api.http` annotation on the gRPC method. +/// +/// Each mapping specifies a URL path template and an HTTP method. The path +/// template may refer to one or more fields in the gRPC request message, as long +/// as each field is a non-repeated field with a primitive (non-message) type. +/// The path template controls how fields of the request message are mapped to +/// the URL path. +/// +/// Example: +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// get: "/v1/{name=messages/*}" +/// }; +/// } +/// } +/// message GetMessageRequest { +/// string name = 1; // Mapped to URL path. +/// } +/// message Message { +/// string text = 1; // The resource content. +/// } +/// +/// This enables an HTTP REST to gRPC mapping as below: +/// +/// HTTP | gRPC +/// -----|----- +/// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +/// +/// Any fields in the request message which are not bound by the path template +/// automatically become HTTP query parameters if there is no HTTP request body. +/// For example: +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// get:"/v1/messages/{message_id}" +/// }; +/// } +/// } +/// message GetMessageRequest { +/// message SubMessage { +/// string subfield = 1; +/// } +/// string message_id = 1; // Mapped to URL path. +/// int64 revision = 2; // Mapped to URL query parameter `revision`. +/// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +/// } +/// +/// This enables a HTTP JSON to RPC mapping as below: +/// +/// HTTP | gRPC +/// -----|----- +/// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +/// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +/// "foo"))` +/// +/// Note that fields which are mapped to URL query parameters must have a +/// primitive type or a repeated primitive type or a non-repeated message type. +/// In the case of a repeated type, the parameter can be repeated in the URL +/// as `...?param=A¶m=B`. In the case of a message type, each field of the +/// message is mapped to a separate parameter, such as +/// `...?foo.a=A&foo.b=B&foo.c=C`. +/// +/// For HTTP methods that allow a request body, the `body` field +/// specifies the mapping. Consider a REST update method on the +/// message resource collection: +/// +/// service Messaging { +/// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// patch: "/v1/messages/{message_id}" +/// body: "message" +/// }; +/// } +/// } +/// message UpdateMessageRequest { +/// string message_id = 1; // mapped to the URL +/// Message message = 2; // mapped to the body +/// } +/// +/// The following HTTP JSON to RPC mapping is enabled, where the +/// representation of the JSON in the request body is determined by +/// protos JSON encoding: +/// +/// HTTP | gRPC +/// -----|----- +/// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +/// "123456" message { text: "Hi!" })` +/// +/// The special name `*` can be used in the body mapping to define that +/// every field not bound by the path template should be mapped to the +/// request body. This enables the following alternative definition of +/// the update method: +/// +/// service Messaging { +/// rpc UpdateMessage(Message) returns (Message) { +/// option (google.api.http) = { +/// patch: "/v1/messages/{message_id}" +/// body: "*" +/// }; +/// } +/// } +/// message Message { +/// string message_id = 1; +/// string text = 2; +/// } +/// +/// +/// The following HTTP JSON to RPC mapping is enabled: +/// +/// HTTP | gRPC +/// -----|----- +/// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +/// "123456" text: "Hi!")` +/// +/// Note that when using `*` in the body mapping, it is not possible to +/// have HTTP parameters, as all fields not bound by the path end in +/// the body. This makes this option more rarely used in practice when +/// defining REST APIs. The common usage of `*` is in custom methods +/// which don't use the URL at all for transferring data. +/// +/// It is possible to define multiple HTTP methods for one RPC by using +/// the `additional_bindings` option. Example: +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// get: "/v1/messages/{message_id}" +/// additional_bindings { +/// get: "/v1/users/{user_id}/messages/{message_id}" +/// } +/// }; +/// } +/// } +/// message GetMessageRequest { +/// string message_id = 1; +/// string user_id = 2; +/// } +/// +/// This enables the following two alternative HTTP JSON to RPC mappings: +/// +/// HTTP | gRPC +/// -----|----- +/// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +/// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +/// "123456")` +/// +/// ## Rules for HTTP mapping +/// +/// 1. Leaf request fields (recursive expansion nested messages in the request +/// message) are classified into three categories: +/// - Fields referred by the path template. They are passed via the URL path. +/// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They +/// are passed via the HTTP +/// request body. +/// - All other fields are passed via the URL query parameters, and the +/// parameter name is the field path in the request message. A repeated +/// field can be represented as multiple query parameters under the same +/// name. +/// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL +/// query parameter, all fields +/// are passed via URL path and HTTP request body. +/// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP +/// request body, all +/// fields are passed via URL path and URL query parameters. +/// +/// ### Path template syntax +/// +/// Template = "/" Segments \[ Verb \] ; +/// Segments = Segment { "/" Segment } ; +/// Segment = "*" | "**" | LITERAL | Variable ; +/// Variable = "{" FieldPath \[ "=" Segments \] "}" ; +/// FieldPath = IDENT { "." IDENT } ; +/// Verb = ":" LITERAL ; +/// +/// The syntax `*` matches a single URL path segment. The syntax `**` matches +/// zero or more URL path segments, which must be the last part of the URL path +/// except the `Verb`. +/// +/// The syntax `Variable` matches part of the URL path as specified by its +/// template. A variable template must not contain other variables. If a variable +/// matches a single path segment, its template may be omitted, e.g. `{var}` +/// is equivalent to `{var=*}`. +/// +/// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +/// contains any reserved character, such characters should be percent-encoded +/// before the matching. +/// +/// If a variable contains exactly one path segment, such as `"{var}"` or +/// `"{var=*}"`, when such a variable is expanded into a URL path on the client +/// side, all characters except `\[-_.~0-9a-zA-Z\]` are percent-encoded. The +/// server side does the reverse decoding. Such variables show up in the +/// [Discovery +/// Document]() as +/// `{var}`. +/// +/// If a variable contains multiple path segments, such as `"{var=foo/*}"` +/// or `"{var=**}"`, when such a variable is expanded into a URL path on the +/// client side, all characters except `\[-_.~/0-9a-zA-Z\]` are percent-encoded. +/// The server side does the reverse decoding, except "%2F" and "%2f" are left +/// unchanged. Such variables show up in the +/// [Discovery +/// Document]() as +/// `{+var}`. +/// +/// ## Using gRPC API Service Configuration +/// +/// gRPC API Service Configuration (service config) is a configuration language +/// for configuring a gRPC service to become a user-facing product. The +/// service config is simply the YAML representation of the `google.api.Service` +/// proto message. +/// +/// As an alternative to annotating your proto file, you can configure gRPC +/// transcoding in your service config YAML files. You do this by specifying a +/// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +/// effect as the proto annotation. This can be particularly useful if you +/// have a proto that is reused in multiple services. Note that any transcoding +/// specified in the service config will override any matching transcoding +/// configuration in the proto. +/// +/// Example: +/// +/// http: +/// rules: +/// # Selects a gRPC method and applies HttpRule to it. +/// - selector: example.v1.Messaging.GetMessage +/// get: /v1/messages/{message_id}/{sub.subfield} +/// +/// ## Special notes +/// +/// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +/// proto to JSON conversion must follow the [proto3 +/// specification](). +/// +/// While the single segment variable follows the semantics of +/// [RFC 6570]() Section 3.2.2 Simple String +/// Expansion, the multi segment variable **does not** follow RFC 6570 Section +/// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +/// does not expand special characters like `?` and `#`, which would lead +/// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +/// for multi segment variables. +/// +/// The path variables **must not** refer to any repeated or mapped field, +/// because client libraries are not capable of handling such variable expansion. +/// +/// The path variables **must not** capture the leading "/" character. The reason +/// is that the most common use case "{var}" does not capture the leading "/" +/// character. For consistency, all path variables must share the same behavior. +/// +/// Repeated message fields must not be mapped to URL query parameters, because +/// no client library can support such complicated mapping. +/// +/// If an API needs to use a JSON array for request or response body, it can map +/// the request or response body to a repeated field. However, some gRPC +/// Transcoding implementations may not support this feature. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HttpRule { + /// Selects a method to which this rule applies. + /// + /// Refer to [selector][google.api.DocumentationRule.selector] for syntax + /// details. + #[prost(string, tag = "1")] + pub selector: ::prost::alloc::string::String, + /// The name of the request field whose value is mapped to the HTTP request + /// body, or `*` for mapping all request fields not captured by the path + /// pattern to the HTTP body, or omitted for not having any HTTP request body. + /// + /// NOTE: the referred field must be present at the top-level of the request + /// message type. + #[prost(string, tag = "7")] + pub body: ::prost::alloc::string::String, + /// Optional. The name of the response field whose value is mapped to the HTTP + /// response body. When omitted, the entire response message will be used + /// as the HTTP response body. + /// + /// NOTE: The referred field must be present at the top-level of the response + /// message type. + #[prost(string, tag = "12")] + pub response_body: ::prost::alloc::string::String, + /// Additional HTTP bindings for the selector. Nested bindings must + /// not contain an `additional_bindings` field themselves (that is, + /// the nesting may only be one level deep). + #[prost(message, repeated, tag = "11")] + pub additional_bindings: ::prost::alloc::vec::Vec, + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[prost(oneof = "http_rule::Pattern", tags = "2, 3, 4, 5, 6, 8")] + pub pattern: ::core::option::Option, +} +/// Nested message and enum types in `HttpRule`. +pub mod http_rule { + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Pattern { + /// Maps to HTTP GET. Used for listing and getting information about + /// resources. + #[prost(string, tag = "2")] + Get(::prost::alloc::string::String), + /// Maps to HTTP PUT. Used for replacing a resource. + #[prost(string, tag = "3")] + Put(::prost::alloc::string::String), + /// Maps to HTTP POST. Used for creating a resource or performing an action. + #[prost(string, tag = "4")] + Post(::prost::alloc::string::String), + /// Maps to HTTP DELETE. Used for deleting a resource. + #[prost(string, tag = "5")] + Delete(::prost::alloc::string::String), + /// Maps to HTTP PATCH. Used for updating a resource. + #[prost(string, tag = "6")] + Patch(::prost::alloc::string::String), + /// The custom pattern is used for specifying an HTTP method that is not + /// included in the `pattern` field, such as HEAD, or "*" to leave the + /// HTTP method unspecified for this rule. The wild-card rule is useful + /// for services that provide content to Web (HTML) clients. + #[prost(message, tag = "8")] + Custom(super::CustomHttpPattern), + } +} +impl ::prost::Name for HttpRule { + const NAME: &'static str = "HttpRule"; + const PACKAGE: &'static str = "google.api"; + fn full_name() -> ::prost::alloc::string::String { + "google.api.HttpRule".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/google.api.HttpRule".into() + } +} +/// A custom pattern is used for defining custom HTTP verb. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CustomHttpPattern { + /// The name of this custom HTTP verb. + #[prost(string, tag = "1")] + pub kind: ::prost::alloc::string::String, + /// The path matched by this custom verb. + #[prost(string, tag = "2")] + pub path: ::prost::alloc::string::String, +} +impl ::prost::Name for CustomHttpPattern { + const NAME: &'static str = "CustomHttpPattern"; + const PACKAGE: &'static str = "google.api"; + fn full_name() -> ::prost::alloc::string::String { + "google.api.CustomHttpPattern".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/google.api.CustomHttpPattern".into() + } +} diff --git a/v4-proto-rs/src/lib.rs b/v4-proto-rs/src/lib.rs new file mode 100644 index 0000000000..0e372c984a --- /dev/null +++ b/v4-proto-rs/src/lib.rs @@ -0,0 +1,45 @@ +/// re-export of cosmos-sdk +pub use cosmos_sdk_proto; + +include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/_includes.rs")); + +use prost::Name; + +pub trait ToAny: Name + Sized { + /// Converts the type to `prost_types::Any`. + fn to_any(self) -> prost_types::Any { + let value = self.encode_to_vec(); + let type_url = Self::type_url(); + prost_types::Any { type_url, value } + } +} + +impl ToAny for M {} + +#[cfg(test)] +mod test { + use super::ToAny; + use crate::cosmos_sdk_proto::cosmos::bank::v1beta1::MsgSend; + use crate::dydxprotocol::clob::MsgCancelOrder; + + #[test] + pub fn test_any_conversion() { + /// Tests the conversion of `MsgCancelOrder` to `prost_types::Any`. + let msg = MsgCancelOrder { + order_id: None, + good_til_oneof: None, + }; + let any = msg.to_any(); + let url = "/dydxprotocol.clob.MsgCancelOrder"; + assert_eq!(any.type_url, url); + } + + #[test] + pub fn test_any_conversion_wrapped() { + /// Tests the conversion of `MsgSend` to `prost_types::Any`. + let msg = MsgSend::default(); + let any = msg.to_any(); + let url = "/cosmos.bank.v1beta1.MsgSend"; + assert_eq!(any.type_url, url); + } +} From 04b05b5aa666c8c861d5f7dca96e0c6bfcf5be83 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Tue, 22 Oct 2024 14:48:57 -0400 Subject: [PATCH 097/120] Bump SDK - Always Reset OE (#2531) --- protocol/go.mod | 2 +- protocol/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/go.mod b/protocol/go.mod index 1d940dd105..2ea2c9af98 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -470,7 +470,7 @@ replace ( // Use dYdX fork of CometBFT github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf // Use dYdX fork of Cosmos SDK - github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703 + github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241022180223-cc8c850952c5 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 c3fea57229..e787715efe 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -961,8 +961,8 @@ github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf h1:pdKqF/qshVtVxcCfpK93QSUIIV3UjR/zj0RfPuqFPwU= github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703 h1:4bNZ3j0dhbxWfqyEKc0sC2377m+t+wFuFDocqig9VLo= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240808180557-4b1c1dc17703/go.mod h1:TWUDGvgHJ49+QI6WOf03km3TuUOoAplzgnsjGQH3L7s= +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/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= From a4b96d86d800935ba1eb9acd529146794775be63 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:09:33 -0400 Subject: [PATCH 098/120] [CT-1262] add e2e tests for permissioned keys success cases (#2479) --- protocol/app/ante.go | 39 +- protocol/app/ante/pubkey.go | 110 +++ protocol/app/app.go | 44 +- .../testutil/constants/stateful_orders.go | 12 + .../x/accountplus/ante/circuit_breaker.go | 16 +- .../accountplus/ante/circuit_breaker_test.go | 4 +- .../authenticator/signature_authenticator.go | 6 + .../affiliates/e2e/register_affiliate_test.go | 6 +- protocol/x/clob/e2e/permissioned_keys_test.go | 761 ++++++++++++++++++ 9 files changed, 939 insertions(+), 59 deletions(-) create mode 100644 protocol/app/ante/pubkey.go diff --git a/protocol/app/ante.go b/protocol/app/ante.go index b00c48e157..156d245138 100644 --- a/protocol/app/ante.go +++ b/protocol/app/ante.go @@ -124,15 +124,22 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ), sigVerification: accountplusante.NewCircuitBreakerDecorator( options.Codec, - accountplusante.NewAuthenticatorDecorator( - options.Codec, - options.AccountplusKeeper, - options.AccountKeeper, - options.SignModeHandler, + sdk.ChainAnteDecorators( + customante.NewEmitPubKeyEventsDecorator(), + accountplusante.NewAuthenticatorDecorator( + options.Codec, + options.AccountplusKeeper, + options.AccountKeeper, + options.SignModeHandler, + ), ), - customante.NewSigVerificationDecorator( - options.AccountKeeper, - options.SignModeHandler, + sdk.ChainAnteDecorators( + ante.NewSetPubKeyDecorator(options.AccountKeeper), + ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), + customante.NewSigVerificationDecorator( + options.AccountKeeper, + options.SignModeHandler, + ), ), ), consumeTxSizeGas: ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), @@ -142,8 +149,6 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { options.FeegrantKeeper, options.TxFeeChecker, ), - setPubKey: ante.NewSetPubKeyDecorator(options.AccountKeeper), - sigGasConsume: ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), clobRateLimit: clobante.NewRateLimitDecorator(options.ClobKeeper), clob: clobante.NewClobDecorator(options.ClobKeeper), marketUpdates: customante.NewValidateMarketUpdateDecorator( @@ -175,8 +180,6 @@ type lockingAnteHandler struct { sigVerification accountplusante.CircuitBreakerDecorator consumeTxSizeGas ante.ConsumeTxSizeGasDecorator deductFee ante.DeductFeeDecorator - setPubKey ante.SetPubKeyDecorator - sigGasConsume ante.SigGasConsumeDecorator clobRateLimit clobante.ClobRateLimitDecorator clob clobante.ClobDecorator marketUpdates customante.ValidateMarketUpdateDecorator @@ -252,15 +255,9 @@ func (h *lockingAnteHandler) clobAnteHandle(ctx sdk.Context, tx sdk.Tx, simulate if ctx, err = h.consumeTxSizeGas.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } - if ctx, err = h.setPubKey.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { - return ctx, err - } if ctx, err = h.validateSigCount.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } - if ctx, err = h.sigGasConsume.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { - return ctx, err - } if ctx, err = h.replayProtection.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } @@ -422,15 +419,9 @@ func (h *lockingAnteHandler) otherMsgAnteHandle(ctx sdk.Context, tx sdk.Tx, simu if ctx, err = h.deductFee.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } - if ctx, err = h.setPubKey.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { - return ctx, err - } if ctx, err = h.validateSigCount.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } - if ctx, err = h.sigGasConsume.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { - return ctx, err - } if ctx, err = h.replayProtection.AnteHandle(ctx, tx, simulate, noOpAnteHandle); err != nil { return ctx, err } diff --git a/protocol/app/ante/pubkey.go b/protocol/app/ante/pubkey.go new file mode 100644 index 0000000000..7dbe315e3c --- /dev/null +++ b/protocol/app/ante/pubkey.go @@ -0,0 +1,110 @@ +package ante + +import ( + "encoding/base64" + "fmt" + + errorsmod "cosmossdk.io/errors" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +// NewEmitPubKeyEventsDecorator emits events for each signer's public key. +// CONTRACT: Tx must implement SigVerifiableTx interface +type EmitPubKeyEventsDecorator struct{} + +func NewEmitPubKeyEventsDecorator() EmitPubKeyEventsDecorator { + return EmitPubKeyEventsDecorator{} +} + +func (eped EmitPubKeyEventsDecorator) AnteHandle( + ctx sdk.Context, + tx sdk.Tx, + simulate bool, + next sdk.AnteHandler, +) (sdk.Context, error) { + sigTx, ok := tx.(authsigning.SigVerifiableTx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") + } + + signers, err := sigTx.GetSigners() + if err != nil { + return ctx, err + } + + signerStrs := make([]string, len(signers)) + + // Also emit the following events, so that txs can be indexed by these + // indices: + // - signature (via `tx.signature=''`), + // - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`). + sigs, err := sigTx.GetSignaturesV2() + if err != nil { + return ctx, err + } + + var events sdk.Events + for i, sig := range sigs { + events = append(events, sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signerStrs[i], sig.Sequence)), + )) + + sigBzs, err := signatureDataToBz(sig.Data) + if err != nil { + return ctx, err + } + for _, sigBz := range sigBzs { + events = append(events, sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)), + )) + } + } + + ctx.EventManager().EmitEvents(events) + + return next(ctx, tx, simulate) +} + +// signatureDataToBz converts a SignatureData into raw bytes signature. +// For SingleSignatureData, it returns the signature raw bytes. +// For MultiSignatureData, it returns an array of all individual signatures, +// as well as the aggregated signature. +func signatureDataToBz(data signing.SignatureData) ([][]byte, error) { + if data == nil { + return nil, fmt.Errorf("got empty SignatureData") + } + + switch data := data.(type) { + case *signing.SingleSignatureData: + return [][]byte{data.Signature}, nil + case *signing.MultiSignatureData: + sigs := [][]byte{} + var err error + + for _, d := range data.Signatures { + nestedSigs, err := signatureDataToBz(d) + if err != nil { + return nil, err + } + sigs = append(sigs, nestedSigs...) + } + + multiSignature := cryptotypes.MultiSignature{ + Signatures: sigs, + } + aggregatedSig, err := multiSignature.Marshal() + if err != nil { + return nil, err + } + sigs = append(sigs, aggregatedSig) + + return sigs, nil + default: + return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data) + } +} diff --git a/protocol/app/app.go b/protocol/app/app.go index c0518c81f0..89a10ce846 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1113,6 +1113,28 @@ func New( app.SubaccountsKeeper, ) + // Initialize authenticators + app.AuthenticatorManager = authenticator.NewAuthenticatorManager() + app.AuthenticatorManager.InitializeAuthenticators( + []accountplusmoduletypes.Authenticator{ + authenticator.NewAllOf(app.AuthenticatorManager), + authenticator.NewAnyOf(app.AuthenticatorManager), + authenticator.NewSignatureVerification(app.AccountKeeper), + authenticator.NewMessageFilter(), + authenticator.NewClobPairIdFilter(), + authenticator.NewSubaccountFilter(), + }, + ) + app.AccountPlusKeeper = *accountplusmodulekeeper.NewKeeper( + appCodec, + keys[accountplusmoduletypes.StoreKey], + app.AuthenticatorManager, + []string{ + lib.GovModuleAddress.String(), + }, + ) + accountplusModule := accountplusmodule.NewAppModule(appCodec, app.AccountPlusKeeper) + clobFlags := clobflags.GetClobFlagValuesFromOptions(appOpts) logger.Info("Parsed CLOB flags", "Flags", clobFlags) @@ -1232,28 +1254,6 @@ func New( app.VaultKeeper, ) - // Initialize authenticators - app.AuthenticatorManager = authenticator.NewAuthenticatorManager() - app.AuthenticatorManager.InitializeAuthenticators( - []accountplusmoduletypes.Authenticator{ - authenticator.NewAllOf(app.AuthenticatorManager), - authenticator.NewAnyOf(app.AuthenticatorManager), - authenticator.NewSignatureVerification(app.AccountKeeper), - authenticator.NewMessageFilter(), - authenticator.NewClobPairIdFilter(), - authenticator.NewSubaccountFilter(), - }, - ) - app.AccountPlusKeeper = *accountplusmodulekeeper.NewKeeper( - appCodec, - keys[accountplusmoduletypes.StoreKey], - app.AuthenticatorManager, - []string{ - lib.GovModuleAddress.String(), - }, - ) - accountplusModule := accountplusmodule.NewAppModule(appCodec, app.AccountPlusKeeper) - /**** Module Options ****/ // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment diff --git a/protocol/testutil/constants/stateful_orders.go b/protocol/testutil/constants/stateful_orders.go index 3c9450ee2b..3e0eb8a80d 100644 --- a/protocol/testutil/constants/stateful_orders.go +++ b/protocol/testutil/constants/stateful_orders.go @@ -294,6 +294,18 @@ var ( Subticks: 30, GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{GoodTilBlockTime: 10}, } + LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10 = clobtypes.Order{ + OrderId: clobtypes.OrderId{ + SubaccountId: Bob_Num0, + ClientId: 0, + OrderFlags: clobtypes.OrderIdFlags_LongTerm, + ClobPairId: 1, + }, + Side: clobtypes.Order_SIDE_BUY, + Quantums: 25, + Subticks: 30, + GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{GoodTilBlockTime: 10}, + } LongTermOrder_Bob_Num0_Id0_Clob0_Buy35_Price30_GTBT11 = clobtypes.Order{ OrderId: clobtypes.OrderId{ SubaccountId: Bob_Num0, diff --git a/protocol/x/accountplus/ante/circuit_breaker.go b/protocol/x/accountplus/ante/circuit_breaker.go index 95eebb429a..0d02c52612 100644 --- a/protocol/x/accountplus/ante/circuit_breaker.go +++ b/protocol/x/accountplus/ante/circuit_breaker.go @@ -11,20 +11,20 @@ import ( // the existence of `TxExtension`. type CircuitBreakerDecorator struct { cdc codec.BinaryCodec - authenticatorAnteHandlerFlow sdk.AnteDecorator - originalAnteHandlerFlow sdk.AnteDecorator + authenticatorAnteHandlerFlow sdk.AnteHandler + defaultAnteHandlerFlow sdk.AnteHandler } // NewCircuitBreakerDecorator creates a new instance of CircuitBreakerDecorator with the provided parameters. func NewCircuitBreakerDecorator( cdc codec.BinaryCodec, - auth sdk.AnteDecorator, - classic sdk.AnteDecorator, + authenticatorAnteHandlerFlow sdk.AnteHandler, + defaultAnteHandlerFlow sdk.AnteHandler, ) CircuitBreakerDecorator { return CircuitBreakerDecorator{ cdc: cdc, - authenticatorAnteHandlerFlow: auth, - originalAnteHandlerFlow: classic, + authenticatorAnteHandlerFlow: authenticatorAnteHandlerFlow, + defaultAnteHandlerFlow: defaultAnteHandlerFlow, } } @@ -44,9 +44,9 @@ func (ad CircuitBreakerDecorator) AnteHandle( // Check that the authenticator flow is active if specified, _ := lib.HasSelectedAuthenticatorTxExtensionSpecified(tx, ad.cdc); specified { // Return and call the AnteHandle function on all the authenticator decorators. - return ad.authenticatorAnteHandlerFlow.AnteHandle(ctx, tx, simulate, next) + return ad.authenticatorAnteHandlerFlow(ctx, tx, simulate) } // Return and call the AnteHandle function on all the original decorators. - return ad.originalAnteHandlerFlow.AnteHandle(ctx, tx, simulate, next) + return ad.defaultAnteHandlerFlow(ctx, tx, simulate) } diff --git a/protocol/x/accountplus/ante/circuit_breaker_test.go b/protocol/x/accountplus/ante/circuit_breaker_test.go index 3b554911c9..8b96f38951 100644 --- a/protocol/x/accountplus/ante/circuit_breaker_test.go +++ b/protocol/x/accountplus/ante/circuit_breaker_test.go @@ -151,8 +151,8 @@ func (s *AuthenticatorCircuitBreakerAnteSuite) TestCircuitBreakerAnte() { // Create a CircuitBreaker AnteDecorator cbd := ante.NewCircuitBreakerDecorator( s.tApp.App.AppCodec(), - mockTestAuthenticator, - mockTestClassic, + sdk.ChainAnteDecorators(mockTestAuthenticator), + sdk.ChainAnteDecorators(mockTestClassic), ) anteHandler := sdk.ChainAnteDecorators(cbd) diff --git a/protocol/x/accountplus/authenticator/signature_authenticator.go b/protocol/x/accountplus/authenticator/signature_authenticator.go index 9e7d759cd9..90a1785e2b 100644 --- a/protocol/x/accountplus/authenticator/signature_authenticator.go +++ b/protocol/x/accountplus/authenticator/signature_authenticator.go @@ -56,6 +56,12 @@ func (sva SignatureVerification) Initialize(config []byte) (types.Authenticator, // Authenticate takes a SignaturesVerificationData struct and validates // each signer and signature using signature verification func (sva SignatureVerification) Authenticate(ctx sdk.Context, request types.AuthenticationRequest) error { + // First consume gas for verifying the signature + params := sva.ak.GetParams(ctx) + // Signature verification only accepts secp256k1 signatures so consume static gas here. + ctx.GasMeter().ConsumeGas(params.SigVerifyCostSecp256k1, "secp256k1 signature verification") + + // after gas consumption continue to verify signatures if request.Simulate || ctx.IsReCheckTx() { return nil } diff --git a/protocol/x/affiliates/e2e/register_affiliate_test.go b/protocol/x/affiliates/e2e/register_affiliate_test.go index 5408d56b02..56753ae1c9 100644 --- a/protocol/x/affiliates/e2e/register_affiliate_test.go +++ b/protocol/x/affiliates/e2e/register_affiliate_test.go @@ -10,9 +10,6 @@ import ( ) func TestRegisterAffiliateInvalidSigner(t *testing.T) { - tApp := testapp.NewTestAppBuilder(t).Build() - ctx := tApp.InitChain() - testCases := []struct { name string referee string @@ -45,6 +42,9 @@ func TestRegisterAffiliateInvalidSigner(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).Build() + ctx := tApp.InitChain() + msgRegisterAffiliate := types.MsgRegisterAffiliate{ Referee: tc.referee, Affiliate: tc.affiliate, diff --git a/protocol/x/clob/e2e/permissioned_keys_test.go b/protocol/x/clob/e2e/permissioned_keys_test.go index 18007beda5..87193be2ce 100644 --- a/protocol/x/clob/e2e/permissioned_keys_test.go +++ b/protocol/x/clob/e2e/permissioned_keys_test.go @@ -662,3 +662,764 @@ func TestPlaceOrder_PermissionedKeys_Failures(t *testing.T) { }) } } + +func TestPlaceOrder_PermissionedKeys_Success(t *testing.T) { + config := []aptypes.SubAuthenticatorInitData{ + { + Type: "SignatureVerification", + Config: constants.AlicePrivateKey.PubKey().Bytes(), + }, + { + Type: "MessageFilter", + Config: []byte("/dydxprotocol.clob.MsgPlaceOrder"), + }, + { + Type: "ClobPairIdFilter", + Config: []byte("0,1"), + }, + { + Type: "SubaccountFilter", + Config: []byte("0,1"), + }, + } + compositeAuthenticatorConfig, err := json.Marshal(config) + require.NoError(t, err) + + tests := map[string]struct { + smartAccountEnabled bool + blocks []TestBlockWithMsgs + + expectedOrderIdsInMemclob map[clobtypes.OrderId]bool + expectedOrderFillAmounts map[clobtypes.OrderId]uint64 + }{ + "Short term order placed via permissioned keys can be added to the orderbook": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: true, + }, + }, + "Stateful order placed via permissioned keys can be added to the orderbook": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.LongTermOrder_Bob_Num0_Id0_Clob0_Buy25_Price30_GTBT10, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.LongTermOrder_Bob_Num0_Id0_Clob0_Buy25_Price30_GTBT10.OrderId: true, + }, + }, + "Short term maker order placed via permissioned keys can be matched": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: 5000, // full size of scaled orders + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: 5000, + }, + }, + "Stateful maker order placed via permissioned keys can be matched": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: true, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: 5000, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: 5000, + }, + }, + "Short term taker order placed via permissioned keys can be matched": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: 5000, // full size of scaled orders + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15.OrderId: 5000, + }, + }, + "Stateful taker order placed via permissioned keys can be matched": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: true, + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: 5000, + constants.Order_Alice_Num0_Id2_Clob1_Sell5_Price10_GTB15.OrderId: 5000, + }, + }, + "Short term maker order is removed if permissioned key is removed": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{0}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgRemoveAuthenticator{ + Sender: constants.BobAccAddress.String(), + Id: 0, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 8, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: false, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.Order_Bob_Num0_Id11_Clob1_Buy5_Price40_GTB20.OrderId: 0, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: 0, + }, + }, + // Short term maker orders are explicitly removed when the permissioned key is removed. This + // is because short term orders go through another round of ante handler check during `DeliverTx` + // and we have to maintain the invariant that the operations queue is always valid. + // + // On contrast, stateful orders don't go through ante handlers and therefore we can allow these orders + // to be matched optimistically. + "Stateful maker order can be matched even if permissioned key is removed": { + smartAccountEnabled: true, + blocks: []TestBlockWithMsgs{ + { + Block: 2, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgAddAuthenticator{ + Sender: constants.BobAccAddress.String(), + AuthenticatorType: "AllOf", + Data: compositeAuthenticatorConfig, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{1}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 4, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10, + testapp.DefaultGenesis(), + ), + ), + }, + Authenticators: []uint64{0}, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{1}, + SeqNum: []uint64{2}, + // Sign using Alice's private key. + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 6, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + &aptypes.MsgRemoveAuthenticator{ + Sender: constants.BobAccAddress.String(), + Id: 0, + }, + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 300_000, + AccountNum: []uint64{1}, + SeqNum: []uint64{3}, + Signers: []cryptotypes.PrivKey{constants.BobPrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + { + Block: 8, + Msgs: []TestSdkMsg{ + { + Msg: []sdk.Msg{ + clobtypes.NewMsgPlaceOrder( + testapp.MustScaleOrder( + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC, + testapp.DefaultGenesis(), + ), + ), + }, + + Fees: constants.TestFeeCoins_5Cents, + Gas: 0, + AccountNum: []uint64{0}, + SeqNum: []uint64{0}, + Signers: []cryptotypes.PrivKey{constants.AlicePrivateKey}, + + ExpectedRespCode: 0, + }, + }, + }, + }, + expectedOrderIdsInMemclob: map[clobtypes.OrderId]bool{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: true, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: false, + }, + expectedOrderFillAmounts: map[clobtypes.OrderId]uint64{ + constants.LongTermOrder_Bob_Num0_Id0_Clob1_Buy25_Price30_GTBT10.OrderId: 5000, + constants.Order_Alice_Num0_Id1_Clob1_Sell5_Price15_GTB20_IOC.OrderId: 5000, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn(func() (genesis types.GenesisDoc) { + genesis = testapp.DefaultGenesis() + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *aptypes.GenesisState) { + genesisState.Params.IsSmartAccountActive = tc.smartAccountEnabled + }, + ) + return genesis + }).Build() + ctx := tApp.InitChain() + + lastBlockHeight := uint32(0) + for _, block := range tc.blocks { + for _, msg := range block.Msgs { + tx, err := testtx.GenTx( + ctx, + tApp.App.TxConfig(), + msg.Msg, + msg.Fees, + msg.Gas, + tApp.App.ChainID(), + msg.AccountNum, + msg.SeqNum, + msg.Signers, + msg.Signers, + msg.Authenticators, + ) + require.NoError(t, err) + + bytes, err := tApp.App.TxConfig().TxEncoder()(tx) + if err != nil { + panic(err) + } + checkTxReq := abcitypes.RequestCheckTx{ + Tx: bytes, + Type: abcitypes.CheckTxType_New, + } + + resp := tApp.CheckTx(checkTxReq) + require.Equal( + t, + msg.ExpectedRespCode, + resp.Code, + "Response code was not as expected", + ) + require.Contains( + t, + resp.Log, + msg.ExpectedLog, + "Response log was not as expected", + ) + } + ctx = tApp.AdvanceToBlock(block.Block, testapp.AdvanceToBlockOptions{}) + lastBlockHeight = block.Block + } + + ctx = tApp.AdvanceToBlock(lastBlockHeight+2, testapp.AdvanceToBlockOptions{}) + + for orderId, shouldHaveOrder := range tc.expectedOrderIdsInMemclob { + _, exists := tApp.App.ClobKeeper.MemClob.GetOrder(orderId) + require.Equal(t, shouldHaveOrder, exists) + } + + for orderId, expectedFillAmount := range tc.expectedOrderFillAmounts { + _, fillAmount, _ := tApp.App.ClobKeeper.GetOrderFillAmount(ctx, orderId) + require.Equal(t, expectedFillAmount, fillAmount.ToUint64()) + } + }) + } +} From 99c040e77de1f7e2768b56ecfe5fe0621a06b17d Mon Sep 17 00:00:00 2001 From: v0-e <134806759+v0-e@users.noreply.github.com> Date: Sun, 27 Oct 2024 01:23:05 +0000 Subject: [PATCH 099/120] Change Rust protobufs crate name, license reference (#2541) --- v4-proto-rs/Cargo.toml | 6 +- v4-proto-rs/LICENSE | 801 +++++++++++++++++++++++++++++++++++++++++ v4-proto-rs/README.md | 2 +- v4-proto-rs/deny.toml | 10 +- 4 files changed, 815 insertions(+), 4 deletions(-) create mode 100644 v4-proto-rs/LICENSE diff --git a/v4-proto-rs/Cargo.toml b/v4-proto-rs/Cargo.toml index a76ce4d45c..5d71b9b7e5 100644 --- a/v4-proto-rs/Cargo.toml +++ b/v4-proto-rs/Cargo.toml @@ -1,8 +1,10 @@ [package] -name = "v4-proto-rs" +name = "dydx-proto-rust" version = "0.1.0" edition = "2021" -license = "AGPL-3.0" +description = "Compiled dYdX protobuf files" +repository = "https://github.com/dydxprotocol/v4-chain/tree/main/v4-proto-rs" +license = "LicenseRef-dYdX-Custom" [lib] doctest = false diff --git a/v4-proto-rs/LICENSE b/v4-proto-rs/LICENSE new file mode 100644 index 0000000000..39f2773941 --- /dev/null +++ b/v4-proto-rs/LICENSE @@ -0,0 +1,801 @@ +Copyright (C) 2023 dYdX Trading Inc. + +Subject to your compliance with applicable law and the v4 Terms of Use, available at dydx.exchange/legal, you are granted the right to use the Program or Licensed Work (defined below) under the terms of the GNU Affero General Public License as set forth below; provided, however, that if you violate any such applicable law in your use of the Program or Licensed Work, all of your rights and licenses to use (including any rights to reproduce, distribute, install or modify) the Program or Licensed Work will automatically and immediately terminate. + +The “Program” or “Licensed Work” shall mean any of the following: dydxprotocol/cosmos-sdk, dydxprotocol/cometbft, dydxprotocol/v4-chain, dydxprotocol/v4-clients, dydxprotocol/v4-web, dydxprotocol/v4-abacus, dydxprotocol/v4-localization, dydxprotocol/v4-documentation, and any dYdX or dYdX Trading Inc. repository reflecting a copy of, or link to, this license. + + +The GNU Affero General Public License +Version 3, 19 November 2007 + + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + + Preamble + + + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + + The precise terms and conditions for copying, distribution and +modification follow. + + + + TERMS AND CONDITIONS + + + 0. Definitions. + + + "This License" refers to version 3 of the GNU Affero General Public License. + + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + + A "covered work" means either the unmodified Program or a work based +on the Program. + + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + + + 1. Source Code. + + + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + + + The Corresponding Source for a work in source code form is that +same work. + + + 2. Basic Permissions. + + + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; Section 10 +makes it unnecessary. + + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + + + 4. Conveying Verbatim Copies. + + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with Section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + + 5. Conveying Modified Source Versions. + + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of Section 4, provided that you also meet all of these conditions: + + + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under Section + 7. This requirement modifies the requirement in Section 4 to + "keep intact all notices". + + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable Section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + + + 6. Conveying Non-Source Forms. + + + + You may convey a covered work in object code form under the terms +of Sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with Subsection 6b. + + + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under Subsection 6d. + + + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + + + 7. Additional Terms. + + + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + + + a) Disclaiming warranty or limiting liability differently from the + terms of Sections 15 and 16 of this License; or + + + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of Section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + + + 8. Termination. + + + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of Section 11). + + + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under Section 10. + + + + 9. Acceptance Not Required for Having Copies. + + + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + + + 10. Automatic Licensing of Downstream Recipients. + + + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + + + 11. Patents. + + + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + + + 12. No Surrender of Others' Freedom. + + + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + + + 13. Remote Network Interaction; Use with the GNU General Public License. + + + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + + + 14. Revised Versions of this License. + + + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + + + 15. Disclaimer of Warranty. + + + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + + + 16. Limitation of Liability. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + 17. Interpretation of Sections 15 and 16. + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + +For more information about this software, see https://dydx.exchange. + Copyright (C) 2023 dYdX Trading Inc. diff --git a/v4-proto-rs/README.md b/v4-proto-rs/README.md index 551c7d6ce0..ba6177af9b 100644 --- a/v4-proto-rs/README.md +++ b/v4-proto-rs/README.md @@ -6,7 +6,7 @@ Cargo.toml ```toml [dependencies] -v4-proto-rs = "0.1" +dydx-proto-rust = "0.1" ``` *Note:* by default, rust stub files are not rebuilt (see Q&A below) diff --git a/v4-proto-rs/deny.toml b/v4-proto-rs/deny.toml index 198bd0af13..7042a071c7 100644 --- a/v4-proto-rs/deny.toml +++ b/v4-proto-rs/deny.toml @@ -25,10 +25,18 @@ allow = [ "ISC", "Unicode-DFS-2016", "OpenSSL", + "LicenseRef-dYdX-Custom", ] confidence-threshold = 0.8 exceptions = [] +[[licenses.clarify]] +crate = "dydx-proto-rust" +expression = "LicenseRef-dYdX-Custom" +license-files = [ + { path = "LICENSE", hash = 0x30bcd1e3 }, +] + [[licenses.clarify]] name = "ring" expression = "MIT AND ISC AND OpenSSL" @@ -53,4 +61,4 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"] [sources.allow-org] github = [] gitlab = [] -bitbucket = [] \ No newline at end of file +bitbucket = [] From 9ecd3842cb65393749cb1a06ad2c89bf5cbe8bb6 Mon Sep 17 00:00:00 2001 From: v0-e <134806759+v0-e@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:34:20 +0000 Subject: [PATCH 100/120] Use Rust proto crate name as `dydx-proto` (#2543) --- v4-proto-rs/Cargo.toml | 2 +- v4-proto-rs/README.md | 2 +- v4-proto-rs/deny.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/v4-proto-rs/Cargo.toml b/v4-proto-rs/Cargo.toml index 5d71b9b7e5..8c2e82dd60 100644 --- a/v4-proto-rs/Cargo.toml +++ b/v4-proto-rs/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "dydx-proto-rust" +name = "dydx-proto" version = "0.1.0" edition = "2021" description = "Compiled dYdX protobuf files" diff --git a/v4-proto-rs/README.md b/v4-proto-rs/README.md index ba6177af9b..9f95646255 100644 --- a/v4-proto-rs/README.md +++ b/v4-proto-rs/README.md @@ -6,7 +6,7 @@ Cargo.toml ```toml [dependencies] -dydx-proto-rust = "0.1" +dydx-proto = "0.1" ``` *Note:* by default, rust stub files are not rebuilt (see Q&A below) diff --git a/v4-proto-rs/deny.toml b/v4-proto-rs/deny.toml index 7042a071c7..1a29f79813 100644 --- a/v4-proto-rs/deny.toml +++ b/v4-proto-rs/deny.toml @@ -31,7 +31,7 @@ confidence-threshold = 0.8 exceptions = [] [[licenses.clarify]] -crate = "dydx-proto-rust" +crate = "dydx-proto" expression = "LicenseRef-dYdX-Custom" license-files = [ { path = "LICENSE", hash = 0x30bcd1e3 }, From 412eece3d5d7edbba4fac214fb9774f6e2fd2ddd Mon Sep 17 00:00:00 2001 From: vincentwschau <99756290+vincentwschau@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:30:34 -0400 Subject: [PATCH 101/120] De-duplicate and filter out invalid pnl ticks for megavault. (#2540) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Adam Fraser Co-authored-by: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com> Co-authored-by: roy-dydx <133032749+roy-dydx@users.noreply.github.com> Co-authored-by: Mohammed Affan --- indexer/services/comlink/__tests__/lib/helpers.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indexer/services/comlink/__tests__/lib/helpers.test.ts b/indexer/services/comlink/__tests__/lib/helpers.test.ts index bdbb4e70c3..03d169db35 100644 --- a/indexer/services/comlink/__tests__/lib/helpers.test.ts +++ b/indexer/services/comlink/__tests__/lib/helpers.test.ts @@ -876,7 +876,7 @@ describe('helpers', () => { ), }; const blockHeight2: string = '80'; - const blockTime2: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').plus({ minute: 61 }).toISO(); + const blockTime2: string = DateTime.fromISO(pnlTick.createdAt).plus({ hour: 1 }).toISO(); const pnlTick3: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, id: PnlTicksTable.uuid( @@ -888,7 +888,7 @@ describe('helpers', () => { createdAt: blockTime2, }; const blockHeight3: string = '81'; - const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).startOf('hour').plus({ minute: 62 }).toISO(); + const blockTime3: string = DateTime.fromISO(pnlTick.createdAt).plus({ minute: 61 }).toISO(); const pnlTick4: PnlTicksFromDatabase = { ...testConstants.defaultPnlTick, subaccountId: testConstants.defaultSubaccountId2, From 6b4d9e367719e328bfb694ca8e1e470ed21e1da9 Mon Sep 17 00:00:00 2001 From: Chenyao Yu <4844716+chenyaoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:16:48 -0600 Subject: [PATCH 102/120] [TRA-513] Deprecate exchange config json and min exchanges (#2524) --- .../dydxprotocol/prices/market_param.ts | 12 +- proto/dydxprotocol/prices/market_param.proto | 6 +- protocol/app/ante/market_update_test.go | 10 +- .../price_feed_mutable_market_configs_test.go | 28 +--- .../scripts/genesis/sample_pregenesis.json | 70 --------- protocol/testing/e2e/gov/prices_test.go | 76 ++------- protocol/testing/genesis.sh | 144 ------------------ protocol/x/listing/keeper/listing.go | 10 +- protocol/x/listing/keeper/listing_test.go | 2 - protocol/x/prices/keeper/market_param_test.go | 19 --- protocol/x/prices/keeper/market_test.go | 8 - .../msg_server_update_market_param_test.go | 28 ---- .../x/prices/keeper/slinky_adapter_test.go | 8 +- protocol/x/prices/module_test.go | 7 +- protocol/x/prices/types/genesis_test.go | 90 ++++------- protocol/x/prices/types/market_param.go | 14 -- protocol/x/prices/types/market_param.pb.go | 6 +- protocol/x/prices/types/market_param_test.go | 39 +---- .../message_create_oracle_market_test.go | 48 +----- .../types/message_update_market_param_test.go | 23 +-- 20 files changed, 94 insertions(+), 554 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts index 95ed7d6c89..1bd6ccf456 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/market_param.ts @@ -19,7 +19,7 @@ export interface MarketParam { * represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest * price step (in dollars) that can be recorded. * - * Deprecated since v7.1.x. This value is now determined from the marketmap. + * Deprecated since v8.x. This value is now determined from the marketmap. */ /** @deprecated */ @@ -28,6 +28,8 @@ export interface MarketParam { /** * The minimum number of exchanges that should be reporting a live price for * a price update to be considered valid. + * + * Deprecated since v8.x. This value is now determined from the marketmap. */ minExchanges: number; @@ -40,6 +42,8 @@ export interface MarketParam { /** * A string of json that encodes the configuration for resolving the price * of this market on various exchanges. + * + * Deprecated since v8.x. This is now determined from the marketmap. */ exchangeConfigJson: string; @@ -63,7 +67,7 @@ export interface MarketParamSDKType { * represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest * price step (in dollars) that can be recorded. * - * Deprecated since v7.1.x. This value is now determined from the marketmap. + * Deprecated since v8.x. This value is now determined from the marketmap. */ /** @deprecated */ @@ -72,6 +76,8 @@ export interface MarketParamSDKType { /** * The minimum number of exchanges that should be reporting a live price for * a price update to be considered valid. + * + * Deprecated since v8.x. This value is now determined from the marketmap. */ min_exchanges: number; @@ -84,6 +90,8 @@ export interface MarketParamSDKType { /** * A string of json that encodes the configuration for resolving the price * of this market on various exchanges. + * + * Deprecated since v8.x. This is now determined from the marketmap. */ exchange_config_json: string; diff --git a/proto/dydxprotocol/prices/market_param.proto b/proto/dydxprotocol/prices/market_param.proto index 4b90b2877b..bed51a5ca1 100644 --- a/proto/dydxprotocol/prices/market_param.proto +++ b/proto/dydxprotocol/prices/market_param.proto @@ -19,11 +19,13 @@ message MarketParam { // represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest // price step (in dollars) that can be recorded. // - // Deprecated since v7.1.x. This value is now determined from the marketmap. + // Deprecated since v8.x. This value is now determined from the marketmap. sint32 exponent = 3 [ deprecated = true ]; // The minimum number of exchanges that should be reporting a live price for // a price update to be considered valid. + // + // Deprecated since v8.x. This value is now determined from the marketmap. uint32 min_exchanges = 4; // The minimum allowable change in `price` value that would cause a price @@ -32,5 +34,7 @@ message MarketParam { // A string of json that encodes the configuration for resolving the price // of this market on various exchanges. + // + // Deprecated since v8.x. This is now determined from the marketmap. string exchange_config_json = 6; } diff --git a/protocol/app/ante/market_update_test.go b/protocol/app/ante/market_update_test.go index 28a03ab7b1..d8e804e11f 100644 --- a/protocol/app/ante/market_update_test.go +++ b/protocol/app/ante/market_update_test.go @@ -265,12 +265,10 @@ var ( } testMarketParams = prices_types.MarketParam{ - Id: 0, - Pair: "TESTING-USD", - Exponent: -8, - MinExchanges: 1, - MinPriceChangePpm: 10, - ExchangeConfigJson: `{"test_config_placeholder":{}}`, + Id: 0, + Pair: "TESTING-USD", + Exponent: -8, + MinPriceChangePpm: 10, } ) diff --git a/protocol/daemons/pricefeed/client/types/price_feed_mutable_market_configs_test.go b/protocol/daemons/pricefeed/client/types/price_feed_mutable_market_configs_test.go index 7c92227bb1..bf94c82363 100644 --- a/protocol/daemons/pricefeed/client/types/price_feed_mutable_market_configs_test.go +++ b/protocol/daemons/pricefeed/client/types/price_feed_mutable_market_configs_test.go @@ -3,9 +3,10 @@ package types_test import ( "errors" "fmt" - "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed" "testing" + "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed" + "github.com/dydxprotocol/v4-chain/protocol/daemons/pricefeed/client/types" "github.com/dydxprotocol/v4-chain/protocol/mocks" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" @@ -199,31 +200,6 @@ func TestValidateAndTransformParams_Mixed(t *testing.T) { expectedMutableMarketConfigs: testEmptyMarketConfigs, expectedMutableExchangeConfigs: testEmptyExchangeMarketConfigs, }, - "Invalid: invalid exchangeConfigJson (empty, fails marketParams.Validate)": { - marketParams: []prices_types.MarketParam{{ - Id: 1, - Exponent: -2, - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: "", - }}, - expectedMarketParamErrors: map[types.MarketId]error{ - 1: errors.New("ExchangeConfigJson string is not valid"), - }, - expectedMutableMarketConfigs: testEmptyMarketConfigs, - expectedMutableExchangeConfigs: testEmptyExchangeMarketConfigs, - }, - "Invalid: invalid exchangeConfigJson (not json, fails marketParams.Validate)": { - marketParams: []prices_types.MarketParam{ - validMarketParamWithExchangeConfig("invalid"), - }, - expectedMarketParamErrors: map[types.MarketId]error{ - 1: errors.New("ExchangeConfigJson string is not valid"), - }, - expectedMutableMarketConfigs: testEmptyMarketConfigs, - expectedMutableExchangeConfigs: testEmptyExchangeMarketConfigs, - }, "Invalid: invalid exchangeConfigJson (does not conform to schema)": { marketParams: []prices_types.MarketParam{ validMarketParamWithExchangeConfig(`{"exchanges":"invalid"}`), diff --git a/protocol/scripts/genesis/sample_pregenesis.json b/protocol/scripts/genesis/sample_pregenesis.json index ec979c03d6..d8f14dd9ea 100644 --- a/protocol/scripts/genesis/sample_pregenesis.json +++ b/protocol/scripts/genesis/sample_pregenesis.json @@ -3396,282 +3396,212 @@ "prices": { "market_params": [ { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"BTCUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"BTCUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"BTC-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"btcusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XXBTZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"BTC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"BTC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -5, "id": 0, - "min_exchanges": 3, "min_price_change_ppm": 1000, "pair": "BTC-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"ETHUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"ETHUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"ETH-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"ethusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XETHZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"ETH-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"ETH-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -6, "id": 1, - "min_exchanges": 3, "min_price_change_ppm": 1000, "pair": "ETH-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"LINKUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LINK-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"LINKUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LINK-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 2, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "LINK-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"POLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"POL-USD\"},{\"exchangeName\":\"CryptoCom\",\"ticker\":\"POL_USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"POL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 3, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "POL-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"CRVUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"CRV-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"CRV_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"CRVUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"CRV-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 4, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "CRV-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"SOLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"SOLUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"SOL-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"solusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"SOLUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"SOL-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"SOL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -8, "id": 5, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "SOL-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"ADAUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"ADAUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"ADA-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"ADA_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"adausdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"ADAUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"ADA-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"ADA-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 6, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "ADA-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"AVAXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"AVAXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"AVAX-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"AVAX_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"avaxusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"AVAXUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"AVAX-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"AVAX-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -8, "id": 7, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "AVAX-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"FILUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"FIL-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"FIL_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"filusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"FILUSD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"FIL-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 8, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "FIL-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"LTCUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"LTCUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LTC-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"ltcusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XLTCZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LTC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LTC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -8, "id": 9, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "LTC-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"DOGEUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"DOGEUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"DOGE-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"DOGE_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"dogeusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XDGUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"DOGE-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"DOGE-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -11, "id": 10, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "DOGE-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"ATOMUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"ATOMUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"ATOM-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"ATOM_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"ATOMUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"ATOM-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"ATOM-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 11, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "ATOM-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"DOTUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"DOTUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"DOT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"DOT_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"DOTUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"DOT-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"DOT-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 12, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "DOT-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"UNIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"UNIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"UNI-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"UNI_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"UNIUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"UNI-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"UNI-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 13, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "UNI-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"BCHUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"BCHUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"BCH-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"BCH_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"bchusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"BCHUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"BCH-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"BCH-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -7, "id": 14, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "BCH-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"TRXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"TRXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"TRX_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"trxusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"TRXUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"TRX-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"TRX-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -11, "id": 15, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "TRX-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"NEARUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"NEAR-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"NEAR_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"nearusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"NEAR-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"NEAR-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 16, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "NEAR-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"MKRUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"MKR-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"MKRUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"MKR-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"MKR-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -6, "id": 17, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "MKR-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"XLMUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"XLMUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"XLM-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XXLMZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"XLM-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"XLM-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 18, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "XLM-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"ETCUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"ETC-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"ETC_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"etcusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"ETC-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"ETC-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -8, "id": 19, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "ETC-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"COMPUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"COMP-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"COMP_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"COMPUSD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"COMP-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -8, "id": 20, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "COMP-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"WLDUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"WLDUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"WLD_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"wldusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"WLD-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"WLD-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 21, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "WLD-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"APEUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"APE-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"APE_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"APEUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"APE-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"APE-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 22, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "APE-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"APTUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"APTUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"APT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"APT_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"aptusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"APT-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"APT-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 23, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "APT-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"ARBUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"ARBUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"ARB-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"ARB_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"arbusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"ARB-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"ARB-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 24, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "ARB-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"BLUR-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"BLUR_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"BLURUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"BLUR-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"BLUR-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 25, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "BLUR-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"LDOUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"LDO-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"LDOUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"LDO-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"LDO-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 26, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "LDO-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"OPUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"OP-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"OP_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"OP-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"OP-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 27, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "OP-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"PEPEUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"PEPEUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"PEPE_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"PEPEUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"PEPE-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"PEPE-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -16, "id": 28, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "PEPE-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"SEIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"SEIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"SEI-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"SEI_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"seiusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"SEI-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 29, - "min_exchanges": 3, "min_price_change_ppm": 4000, "pair": "SEI-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"SHIBUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"SHIBUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"SHIB-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"SHIB_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"SHIBUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"SHIB-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"SHIB-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -15, "id": 30, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "SHIB-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"SUIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"SUIUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"SUI-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"SUI_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"suiusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"SUI-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"SUI-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 31, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "SUI-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"XRPUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"XRPUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"XRP-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"XRP_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"xrpusdt\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kraken\",\"ticker\":\"XXRPZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"XRP-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"XRP-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -10, "id": 32, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "XRP-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"USDCUSDT\",\"invert\":true},{\"exchangeName\":\"Bybit\",\"ticker\":\"USDCUSDT\",\"invert\":true},{\"exchangeName\":\"CoinbasePro\",\"ticker\":\"USDT-USD\"},{\"exchangeName\":\"Huobi\",\"ticker\":\"ethusdt\",\"adjustByMarket\":\"ETH-USD\",\"invert\":true},{\"exchangeName\":\"Kraken\",\"ticker\":\"USDTZUSD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"BTC-USDT\",\"adjustByMarket\":\"BTC-USD\",\"invert\":true},{\"exchangeName\":\"Okx\",\"ticker\":\"USDC-USDT\",\"invert\":true}]}", "exponent": -9, "id": 1000000, - "min_exchanges": 3, "min_price_change_ppm": 1000, "pair": "USDT-USD" }, { - "exchange_config_json": "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"DYDXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Bybit\",\"ticker\":\"DYDXUSDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Gate\",\"ticker\":\"DYDX_USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Kucoin\",\"ticker\":\"DYDX-USDT\",\"adjustByMarket\":\"USDT-USD\"},{\"exchangeName\":\"Okx\",\"ticker\":\"DYDX-USDT\",\"adjustByMarket\":\"USDT-USD\"}]}", "exponent": -9, "id": 1000001, - "min_exchanges": 3, "min_price_change_ppm": 2500, "pair": "DYDX-USD" } diff --git a/protocol/testing/e2e/gov/prices_test.go b/protocol/testing/e2e/gov/prices_test.go index e1e220e358..debede63c3 100644 --- a/protocol/testing/e2e/gov/prices_test.go +++ b/protocol/testing/e2e/gov/prices_test.go @@ -20,21 +20,15 @@ import ( var ( GENESIS_MARKET_PARAM = pricestypes.MarketParam{ - Id: 0, - Pair: "btc-adv4tnt", - Exponent: -8, - MinExchanges: 2, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: "{}", + Id: 0, + Pair: "btc-adv4tnt", + MinPriceChangePpm: 1_000, } MODIFIED_MARKET_PARAM = pricestypes.MarketParam{ - Id: GENESIS_MARKET_PARAM.Id, - Pair: GENESIS_MARKET_PARAM.Pair, - Exponent: GENESIS_MARKET_PARAM.Exponent, // exponent cannot be updated - MinExchanges: 3, - MinPriceChangePpm: 2_002, - ExchangeConfigJson: `{"exchanges":[{"exchangeName":"Bitfinex","ticker":"tBTCUSD"}]}`, + Id: GENESIS_MARKET_PARAM.Id, + Pair: GENESIS_MARKET_PARAM.Pair, + MinPriceChangePpm: 2_002, } ) @@ -57,12 +51,9 @@ func TestUpdateMarketParam(t *testing.T) { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id + 1, // id does not exist - Pair: MODIFIED_MARKET_PARAM.Pair, - Exponent: MODIFIED_MARKET_PARAM.Exponent, - MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, + Id: MODIFIED_MARKET_PARAM.Id + 1, // id does not exist + Pair: MODIFIED_MARKET_PARAM.Pair, + MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, }, }, expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, @@ -71,12 +62,9 @@ func TestUpdateMarketParam(t *testing.T) { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id, - Pair: "nonexistent-pair", - Exponent: MODIFIED_MARKET_PARAM.Exponent, - MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, + Id: MODIFIED_MARKET_PARAM.Id, + Pair: "nonexistent-pair", + MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, }, }, expectedProposalStatus: govtypesv1.ProposalStatus_PROPOSAL_STATUS_FAILED, @@ -85,40 +73,9 @@ func TestUpdateMarketParam(t *testing.T) { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id, - Pair: "", // invalid - Exponent: MODIFIED_MARKET_PARAM.Exponent, - MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, - }, - }, - expectCheckTxFails: true, - }, - "Failure: min exchanges is 0": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id, - Pair: MODIFIED_MARKET_PARAM.Pair, - Exponent: MODIFIED_MARKET_PARAM.Exponent, - MinExchanges: 0, // invalid - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: MODIFIED_MARKET_PARAM.ExchangeConfigJson, - }, - }, - expectCheckTxFails: true, - }, - "Failure: malformed exchange config json": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: MODIFIED_MARKET_PARAM.Id, - Pair: MODIFIED_MARKET_PARAM.Pair, - Exponent: MODIFIED_MARKET_PARAM.Exponent, - MinExchanges: MODIFIED_MARKET_PARAM.MinExchanges, - MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, - ExchangeConfigJson: `{{"exchanges":[{"exchangeName":"Bitfinex","ticker":"tBTCUSD"}]}`, // invalid + Id: MODIFIED_MARKET_PARAM.Id, + Pair: "", // invalid + MinPriceChangePpm: MODIFIED_MARKET_PARAM.MinPriceChangePpm, }, }, expectCheckTxFails: true, @@ -177,10 +134,7 @@ func TestUpdateMarketParam(t *testing.T) { marketParamPrice := pricestest.GenerateMarketParamPrice( pricestest.WithId(GENESIS_MARKET_PARAM.Id), pricestest.WithPair(GENESIS_MARKET_PARAM.Pair), - pricestest.WithExponent(GENESIS_MARKET_PARAM.Exponent), - pricestest.WithMinExchanges(GENESIS_MARKET_PARAM.MinExchanges), pricestest.WithMinPriceChangePpm(GENESIS_MARKET_PARAM.MinPriceChangePpm), - pricestest.WithExchangeConfigJson(GENESIS_MARKET_PARAM.ExchangeConfigJson), ) genesisState.MarketParams = []pricestypes.MarketParam{marketParamPrice.Param} genesisState.MarketPrices = []pricestypes.MarketPrice{marketParamPrice.Price} diff --git a/protocol/testing/genesis.sh b/protocol/testing/genesis.sh index fbe658ac42..004f9aee5a 100755 --- a/protocol/testing/genesis.sh +++ b/protocol/testing/genesis.sh @@ -1279,525 +1279,385 @@ function edit_genesis() { dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[0].pair' -v 'BTC-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[0].id' -v '0' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[0].exponent' -v '-5' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[0].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[0].min_price_change_ppm' -v '1000' # 0.1% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[0].id' -v '0' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[0].exponent' -v '-5' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[0].price' -v '2868819524' # $28,688 = 1 BTC. - # BTC Exchange Config - btc_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/btc_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[0].exchange_config_json' -v "$btc_exchange_config_json" # Market: ETH-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[1].pair' -v 'ETH-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[1].id' -v '1' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[1].exponent' -v '-6' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[1].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[1].min_price_change_ppm' -v '1000' # 0.1% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[1].id' -v '1' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[1].exponent' -v '-6' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[1].price' -v '1811985252' # $1,812 = 1 ETH. - # ETH Exchange Config - eth_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/eth_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[1].exchange_config_json' -v "$eth_exchange_config_json" # Market: LINK-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[2].pair' -v 'LINK-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[2].id' -v '2' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[2].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[2].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[2].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[2].id' -v '2' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[2].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[2].price' -v '7204646989' # $7.205 = 1 LINK. - # LINK Exchange Config - link_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/link_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[2].exchange_config_json' -v "$link_exchange_config_json" # Market: POL-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].pair' -v 'POL-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[3].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].id' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[3].price' -v '3703925550' # $0.370 = 1 POL. - # POL Exchange Config - pol_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/pol_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[3].exchange_config_json' -v "$pol_exchange_config_json" # Market: CRV-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[4].pair' -v 'CRV-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[4].id' -v '4' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[4].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[4].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[4].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[4].id' -v '4' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[4].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[4].price' -v '6029316660' # $0.6029 = 1 CRV. - # CRV Exchange Config - crv_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/crv_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[4].exchange_config_json' -v "$crv_exchange_config_json" # Market: SOL-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[5].pair' -v 'SOL-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[5].id' -v '5' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[5].exponent' -v '-8' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[5].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[5].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[5].id' -v '5' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[5].exponent' -v '-8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[5].price' -v '2350695125' # $23.51 = 1 SOL. - # SOL Exchange Config - sol_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/sol_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[5].exchange_config_json' -v "$sol_exchange_config_json" # Market: ADA-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[6].pair' -v 'ADA-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[6].id' -v '6' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[6].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[6].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[6].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[6].id' -v '6' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[6].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[6].price' -v '2918831290' # $0.2919 = 1 ADA. - # ADA Exchange Config - ada_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/ada_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[6].exchange_config_json' -v "$ada_exchange_config_json" # Market: AVAX-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[7].pair' -v 'AVAX-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[7].id' -v '7' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[7].exponent' -v '-8' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[7].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[7].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[7].id' -v '7' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[7].exponent' -v '-8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[7].price' -v '1223293720' # $12.23 = 1 AVAX. - # AVAX Exchange Config - avax_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/avax_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[7].exchange_config_json' -v "$avax_exchange_config_json" # Market: FIL-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[8].pair' -v 'FIL-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[8].id' -v '8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[8].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[8].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[8].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[8].id' -v '8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[8].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[8].price' -v '4050336602' # $4.050 = 1 FIL. - # FIL Exchange Config - fil_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/fil_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[8].exchange_config_json' -v "$fil_exchange_config_json" # Market: LTC-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[9].pair' -v 'LTC-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[9].id' -v '9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[9].exponent' -v '-8' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[9].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[9].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[9].id' -v '9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[9].exponent' -v '-8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[9].price' -v '8193604950' # $81.93 = 1 LTC. - # LTC Exchange Config - ltc_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/ltc_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[9].exchange_config_json' -v "$ltc_exchange_config_json" # Market: DOGE-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[10].pair' -v 'DOGE-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[10].id' -v '10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[10].exponent' -v '-11' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[10].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[10].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[10].id' -v '10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[10].exponent' -v '-11' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[10].price' -v '7320836895' # $0.07321 = 1 DOGE. - # DOGE Exchange Config - doge_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/doge_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[10].exchange_config_json' -v "$doge_exchange_config_json" # Market: ATOM-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[11].pair' -v 'ATOM-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[11].id' -v '11' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[11].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[11].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[11].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[11].id' -v '11' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[11].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[11].price' -v '8433494428' # $8.433 = 1 ATOM. - # ATOM Exchange Config - atom_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/atom_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[11].exchange_config_json' -v "$atom_exchange_config_json" # Market: DOT-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[12].pair' -v 'DOT-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[12].id' -v '12' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[12].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[12].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[12].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[12].id' -v '12' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[12].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[12].price' -v '4937186533' # $4.937 = 1 DOT. - # DOT Exchange Config - dot_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/dot_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[12].exchange_config_json' -v "$dot_exchange_config_json" # Market: UNI-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[13].pair' -v 'UNI-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[13].id' -v '13' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[13].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[13].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[13].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[13].id' -v '13' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[13].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[13].price' -v '5852293356' # $5.852 = 1 UNI. - # UNI Exchange Config - uni_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/uni_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[13].exchange_config_json' -v "$uni_exchange_config_json" # Market: BCH-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[14].pair' -v 'BCH-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[14].id' -v '14' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[14].exponent' -v '-7' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[14].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[14].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[14].id' -v '14' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[14].exponent' -v '-7' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[14].price' -v '2255676327' # $225.6 = 1 BCH. - # BCH Exchange Config - bch_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/bch_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[14].exchange_config_json' -v "$bch_exchange_config_json" # Market: TRX-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[15].pair' -v 'TRX-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[15].id' -v '15' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[15].exponent' -v '-11' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[15].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[15].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[15].id' -v '15' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[15].exponent' -v '-11' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[15].price' -v '7795369902' # $0.07795 = 1 TRX. - # TRX Exchange Config - trx_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/trx_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[15].exchange_config_json' -v "$trx_exchange_config_json" # Market: NEAR-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[16].pair' -v 'NEAR-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[16].id' -v '16' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[16].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[16].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[16].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[16].id' -v '16' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[16].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[16].price' -v '1312325536' # $1.312 = 1 NEAR. - # NEAR Exchange Config - near_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/near_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[16].exchange_config_json' -v "$near_exchange_config_json" # Market: MKR-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[17].pair' -v 'MKR-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[17].id' -v '17' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[17].exponent' -v '-6' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[17].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[17].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[17].id' -v '17' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[17].exponent' -v '-6' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[17].price' -v '1199517382' # $1,200 = 1 MKR. - # MKR Exchange Config - mkr_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/mkr_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[17].exchange_config_json' -v "$mkr_exchange_config_json" # Market: XLM-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[18].pair' -v 'XLM-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[18].id' -v '18' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[18].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[18].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[18].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[18].id' -v '18' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[18].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[18].price' -v '1398578933' # $0.1399 = 1 XLM. - # XLM Exchange Config - xlm_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/xlm_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[18].exchange_config_json' -v "$xlm_exchange_config_json" # Market: ETC-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[19].pair' -v 'ETC-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[19].id' -v '19' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[19].exponent' -v '-8' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[19].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[19].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[19].id' -v '19' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[19].exponent' -v '-8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[19].price' -v '1741060746' # $17.41 = 1 ETC. - # ETC Exchange Config - etc_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/etc_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[19].exchange_config_json' -v "$etc_exchange_config_json" # Market: COMP-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[20].pair' -v 'COMP-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[20].id' -v '20' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[20].exponent' -v '-8' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[20].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[20].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[20].id' -v '20' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[20].exponent' -v '-8' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[20].price' -v '5717635307' # $57.18 = 1 COMP. - # COMP Exchange Config - comp_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/comp_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[20].exchange_config_json' -v "$comp_exchange_config_json" # Market: WLD-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[21].pair' -v 'WLD-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[21].id' -v '21' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[21].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[21].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[21].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[21].id' -v '21' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[21].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[21].price' -v '1943019371' # $1.943 = 1 WLD. - # WLD Exchange Config - wld_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/wld_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[21].exchange_config_json' -v "$wld_exchange_config_json" # Market: APE-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[22].pair' -v 'APE-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[22].id' -v '22' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[22].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[22].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[22].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[22].id' -v '22' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[22].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[22].price' -v '1842365656' # $1.842 = 1 APE. - # APE Exchange Config - ape_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/ape_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[22].exchange_config_json' -v "$ape_exchange_config_json" # Market: APT-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[23].pair' -v 'APT-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[23].id' -v '23' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[23].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[23].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[23].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[23].id' -v '23' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[23].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[23].price' -v '6787621897' # $6.788 = 1 APT. - # APT Exchange Config - apt_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/apt_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[23].exchange_config_json' -v "$apt_exchange_config_json" # Market: ARB-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[24].pair' -v 'ARB-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[24].id' -v '24' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[24].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[24].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[24].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[24].id' -v '24' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[24].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[24].price' -v '1127629325' # $1.128 = 1 ARB. - # ARB Exchange Config - arb_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/arb_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[24].exchange_config_json' -v "$arb_exchange_config_json" # Market: BLUR-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[25].pair' -v 'BLUR-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[25].id' -v '25' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[25].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[25].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[25].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[25].id' -v '25' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[25].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[25].price' -v '2779565892' # $.2780 = 1 BLUR. - # BLUR Exchange Config - blur_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/blur_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[25].exchange_config_json' -v "$blur_exchange_config_json" # Market: LDO-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[26].pair' -v 'LDO-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[26].id' -v '26' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[26].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[26].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[26].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[26].id' -v '26' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[26].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[26].price' -v '1855061997' # $1.855 = 1 LDO. - # LDO Exchange Config - ldo_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/ldo_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[26].exchange_config_json' -v "$ldo_exchange_config_json" # Market: OP-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[27].pair' -v 'OP-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[27].id' -v '27' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[27].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[27].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[27].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[27].id' -v '27' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[27].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[27].price' -v '1562218603' # $1.562 = 1 OP. - # OP Exchange Config - op_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/op_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[27].exchange_config_json' -v "$op_exchange_config_json" # Market: PEPE-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[28].pair' -v 'PEPE-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[28].id' -v '28' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[28].exponent' -v '-16' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[28].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[28].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[28].id' -v '28' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[28].exponent' -v '-16' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[28].price' -v '2481900353' # $.000000248190035 = 1 PEPE. - # PEPE Exchange Config - pepe_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/pepe_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[28].exchange_config_json' -v "$pepe_exchange_config_json" # Market: SEI-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[29].pair' -v 'SEI-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[29].id' -v '29' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[29].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[29].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[29].min_price_change_ppm' -v '4000' # 0.4% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[29].id' -v '29' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[29].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[29].price' -v '1686998025' # $.1687 = 1 SEI. - # SEI Exchange Config - sei_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/sei_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[29].exchange_config_json' -v "$sei_exchange_config_json" # Market: SHIB-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[30].pair' -v 'SHIB-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[30].id' -v '30' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[30].exponent' -v '-15' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[30].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[30].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[30].id' -v '30' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[30].exponent' -v '-15' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[30].price' -v '8895882688' # $.000008896 = 1 SHIB. - # SHIB Exchange Config - shib_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/shib_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[30].exchange_config_json' -v "$shib_exchange_config_json" # Market: SUI-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[31].pair' -v 'SUI-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[31].id' -v '31' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[31].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[31].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[31].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[31].id' -v '31' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[31].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[31].price' -v '5896318772' # $.5896 = 1 SUI. - # SUI Exchange Config - sui_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/sui_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[31].exchange_config_json' -v "$sui_exchange_config_json" # Market: XRP-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[32].pair' -v 'XRP-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[32].id' -v '32' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[32].exponent' -v '-10' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[32].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[32].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[32].id' -v '32' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[32].exponent' -v '-10' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[32].price' -v '6327613800' # $.6328 = 1 XRP. - # XRP Exchange Config - xrp_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/xrp_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[32].exchange_config_json' -v "$xrp_exchange_config_json" # Market: USDT-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[33].pair' -v 'USDT-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[33].id' -v '1000000' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[33].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[33].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[33].min_price_change_ppm' -v '1000' # 0.100% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[33].id' -v '1000000' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[33].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[33].price' -v '1000000000' # $1 = 1 USDT. - # USDT Exchange Config - usdt_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/usdt_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[33].exchange_config_json' -v "$usdt_exchange_config_json" # Market: DYDX-USD dasel put -t json -f "$GENESIS" '.app_state.prices.market_params.[]' -v "{}" dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[34].pair' -v 'DYDX-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[34].id' -v '1000001' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[34].exponent' -v '-9' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[34].min_exchanges' -v '3' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.[34].min_price_change_ppm' -v '2500' # 0.25% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[34].id' -v '1000001' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[34].exponent' -v '-9' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.[34].price' -v '2050000000' # $2.05 = 1 DYDX. - # DYDX Exchange Config - dydx_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/dydx_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.[34].exchange_config_json' -v "$dydx_exchange_config_json" # Initialize bridge module account balance as total native token supply. bridge_module_account_balance=$TOTAL_NATIVE_TOKEN_SUPPLY @@ -2379,15 +2239,11 @@ function update_genesis_use_test_volatile_market() { dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.last().pair' -v 'TEST-USD' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.last().id' -v "${TEST_USD_MARKET_ID}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.last().exponent' -v '-5' - dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.last().min_exchanges' -v '1' dasel put -t int -f "$GENESIS" '.app_state.prices.market_params.last().min_price_change_ppm' -v '250' # 0.025% dasel put -t json -f "$GENESIS" '.app_state.prices.market_prices.[]' -v "{}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.last().id' -v "${TEST_USD_MARKET_ID}" dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.last().exponent' -v '-5' dasel put -t int -f "$GENESIS" '.app_state.prices.market_prices.last().price' -v '10000000' # $100 = 1 TEST. - # TEST Exchange Config - test_exchange_config_json=$(cat "$EXCHANGE_CONFIG_JSON_DIR/test_exchange_config.json" | jq -c '.') - dasel put -t string -f "$GENESIS" '.app_state.prices.market_params.last().exchange_config_json' -v "$test_exchange_config_json" # Liquidity Tier: For TEST-USD. 1% leverage and regular 1m nonlinear margin thresholds. NUM_LIQUIDITY_TIERS=$(jq -c '.app_state.perpetuals.liquidity_tiers | length' < ${GENESIS}) diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 4e116b044e..1a126dd527 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -60,13 +60,9 @@ func (k Keeper) CreateMarket( market, err := k.PricesKeeper.CreateMarket( sdkCtx, pricestypes.MarketParam{ - Id: marketId, - Pair: ticker, - // Set the price exponent to the negative of the number of decimals - Exponent: int32(marketMapDetails.Ticker.Decimals) * -1, - MinExchanges: uint32(marketMapDetails.Ticker.MinProviderCount), - MinPriceChangePpm: types.MinPriceChangePpm_LongTail, - ExchangeConfigJson: "{}", // Placeholder. TODO (TRA-513): Deprecate this field + Id: marketId, + Pair: ticker, + MinPriceChangePpm: types.MinPriceChangePpm_LongTail, }, pricestypes.MarketPrice{ Id: marketId, diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index 656fb14aad..18c9a8778f 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -97,8 +97,6 @@ func TestCreateMarket(t *testing.T) { market, exists := pricesKeeper.GetMarketParam(ctx, marketId) require.True(t, exists) require.Equal(t, testMarketParams.Pair, market.Pair) - require.Equal(t, testMarketParams.Exponent, market.Exponent) - require.Equal(t, testMarketParams.MinExchanges, market.MinExchanges) require.Equal(t, testMarketParams.MinPriceChangePpm, types.MinPriceChangePpm_LongTail) } }, diff --git a/protocol/x/prices/keeper/market_param_test.go b/protocol/x/prices/keeper/market_param_test.go index 95644f3b3e..84c71fbcef 100644 --- a/protocol/x/prices/keeper/market_param_test.go +++ b/protocol/x/prices/keeper/market_param_test.go @@ -222,25 +222,6 @@ func TestModifyMarketParam_Errors(t *testing.T) { exchangeConfigJson: validExchangeConfigJson, expectedErr: errorsmod.Wrap(types.ErrInvalidInput, constants.ErrorMsgInvalidMinPriceChange).Error(), }, - "Min exchanges cannot be zero": { - pair: constants.BtcUsdPair, - minExchanges: uint32(0), // cannot be zero - minPriceChangePpm: uint32(50), - exchangeConfigJson: validExchangeConfigJson, - expectedErr: types.ErrZeroMinExchanges.Error(), - }, - "Empty exchange config json string": { - pair: constants.BtcUsdPair, - minExchanges: uint32(1), - minPriceChangePpm: uint32(50), - exchangeConfigJson: "", - expectedErr: errorsmod.Wrapf( - types.ErrInvalidInput, - "ExchangeConfigJson string is not valid: err=%v, input=%v", - "unexpected end of JSON input", - "", - ).Error(), - }, "Updating pair fails due to pair already existing": { targetId: 0, pair: "1-1", diff --git a/protocol/x/prices/keeper/market_test.go b/protocol/x/prices/keeper/market_test.go index f0323f2a57..4b4705d67f 100644 --- a/protocol/x/prices/keeper/market_test.go +++ b/protocol/x/prices/keeper/market_test.go @@ -144,14 +144,6 @@ func TestCreateMarket_Errors(t *testing.T) { price: constants.FiveBillion, expectedErr: errorsmod.Wrap(types.ErrInvalidInput, constants.ErrorMsgInvalidMinPriceChange).Error(), }, - "Min exchanges cannot be zero": { - pair: constants.BtcUsdPair, - minExchanges: uint32(0), // cannot be zero - minPriceChangePpm: uint32(50), - price: constants.FiveBillion, - exchangeConfigJson: validExchangeConfigJson, - expectedErr: types.ErrZeroMinExchanges.Error(), - }, "Market param and price ids don't match": { pair: constants.BtcUsdPair, minExchanges: uint32(2), diff --git a/protocol/x/prices/keeper/msg_server_update_market_param_test.go b/protocol/x/prices/keeper/msg_server_update_market_param_test.go index f0be3bba9a..3164e49524 100644 --- a/protocol/x/prices/keeper/msg_server_update_market_param_test.go +++ b/protocol/x/prices/keeper/msg_server_update_market_param_test.go @@ -80,20 +80,6 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedErr: "Pair cannot be empty", }, - "Failure: update to 0 min exchanges": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: testMarketParam.Id, - Pair: testMarketParam.Pair, - Exponent: testMarketParam.Exponent, - MinExchanges: 0, // invalid - MinPriceChangePpm: testMarketParam.MinPriceChangePpm, - ExchangeConfigJson: testMarketParam.ExchangeConfigJson, - }, - }, - expectedErr: "Min exchanges must be greater than zero", - }, "Failure: update to 0 min price change ppm": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), @@ -108,20 +94,6 @@ func TestUpdateMarketParam(t *testing.T) { }, expectedErr: "Invalid input", }, - "Failure: update to invalid exchange config json": { - msg: &pricestypes.MsgUpdateMarketParam{ - Authority: lib.GovModuleAddress.String(), - MarketParam: pricestypes.MarketParam{ - Id: testMarketParam.Id, - Pair: testMarketParam.Pair, - Exponent: testMarketParam.Exponent, - MinExchanges: testMarketParam.MinExchanges, - MinPriceChangePpm: testMarketParam.MinPriceChangePpm, - ExchangeConfigJson: `{{"exchanges":[{"exchangeName":"XYZ","ticker":"PIKACHU"}]}`, // invalid json - }, - }, - expectedErr: "Invalid input", - }, "Failure: new pair name does not exist in marketmap": { msg: &pricestypes.MsgUpdateMarketParam{ Authority: lib.GovModuleAddress.String(), diff --git a/protocol/x/prices/keeper/slinky_adapter_test.go b/protocol/x/prices/keeper/slinky_adapter_test.go index 017a254899..07dd3872a6 100644 --- a/protocol/x/prices/keeper/slinky_adapter_test.go +++ b/protocol/x/prices/keeper/slinky_adapter_test.go @@ -109,11 +109,9 @@ func TestBadMarketData(t *testing.T) { _, err := keeper.CreateMarket( ctx, types.MarketParam{ - Id: uint32(0), - Pair: "00", - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: "{}", + Id: uint32(0), + Pair: "00", + MinPriceChangePpm: 1, }, types.MarketPrice{}) require.Error(t, err) diff --git a/protocol/x/prices/module_test.go b/protocol/x/prices/module_test.go index 9ddcc5dc96..b9394fb624 100644 --- a/protocol/x/prices/module_test.go +++ b/protocol/x/prices/module_test.go @@ -128,8 +128,8 @@ func TestAppModuleBasic_ValidateGenesisErr(t *testing.T) { }, "Bad state: duplicate market param id": { genesisJson: `{"market_params": [` + - `{"id":0,"pair": "DENT-USD","minExchanges":1,"minPriceChangePpm":1,"exchangeConfigJson":"{}"},` + - `{"id":0,"pair": "LINK-USD","minExchanges":1,"minPriceChangePpm":1,"exchangeConfigJson":"{}"}` + + `{"id":0,"pair": "DENT-USD","minPriceChangePpm":1},` + + `{"id":0,"pair": "LINK-USD","minPriceChangePpm":1}` + `]}`, expectedErr: "duplicated market param id", }, @@ -138,8 +138,7 @@ func TestAppModuleBasic_ValidateGenesisErr(t *testing.T) { expectedErr: errorsmod.Wrap(pricestypes.ErrInvalidInput, "Pair cannot be empty").Error(), }, "Bad state: Mismatch between params and prices": { - genesisJson: `{"market_params": [{"pair": "DENT-USD","minExchanges":1,"minPriceChangePpm":1,` + - `"exchangeConfigJson":"{}"}]}`, + genesisJson: `{"market_params": [{"pair": "DENT-USD","minPriceChangePpm":1}]}`, expectedErr: "expected the same number of market prices and market params", }, } diff --git a/protocol/x/prices/types/genesis_test.go b/protocol/x/prices/types/genesis_test.go index c35803668a..1c953631fc 100644 --- a/protocol/x/prices/types/genesis_test.go +++ b/protocol/x/prices/types/genesis_test.go @@ -2,7 +2,6 @@ package types_test import ( "errors" - "github.com/dydxprotocol/v4-chain/protocol/testutil/daemons/pricefeed/exchange_config" "testing" errorsmod "cosmossdk.io/errors" @@ -25,18 +24,14 @@ func TestGenesisState_Validate(t *testing.T) { genState: &types.GenesisState{ MarketParams: []types.MarketParam{ { - Id: 0, - Pair: constants.BtcUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_BTC_USD], + Id: 0, + Pair: constants.BtcUsdPair, + MinPriceChangePpm: 1, }, { - Id: 1, - Pair: constants.EthUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_ETH_USD], + Id: 1, + Pair: constants.EthUsdPair, + MinPriceChangePpm: 1, }, }, MarketPrices: []types.MarketPrice{ @@ -52,42 +47,18 @@ func TestGenesisState_Validate(t *testing.T) { }, expectedError: nil, }, - "invalid: empty ExchangeConfigJson": { - genState: &types.GenesisState{ - MarketParams: []types.MarketParam{ - { - Id: 0, - Pair: constants.BtcUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: "", - }, - }, - MarketPrices: []types.MarketPrice{ - { - Id: 0, - Price: constants.FiveBillion, - }, - }, - }, - expectedError: errors.New("ExchangeConfigJson string is not valid"), - }, "invalid: duplicate market param ids": { genState: &types.GenesisState{ MarketParams: []types.MarketParam{ { - Id: 0, - Pair: constants.BtcUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_BTC_USD], + Id: 0, + Pair: constants.BtcUsdPair, + MinPriceChangePpm: 1, }, { - Id: 0, - Pair: constants.EthUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_ETH_USD], + Id: 0, + Pair: constants.EthUsdPair, + MinPriceChangePpm: 1, }, }, }, @@ -97,9 +68,8 @@ func TestGenesisState_Validate(t *testing.T) { genState: &types.GenesisState{ MarketParams: []types.MarketParam{ { - Id: 0, - Pair: "", - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_BTC_USD], + Id: 0, + Pair: "", }, }, }, @@ -109,18 +79,14 @@ func TestGenesisState_Validate(t *testing.T) { genState: &types.GenesisState{ MarketParams: []types.MarketParam{ { - Id: 0, - Pair: constants.BtcUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_BTC_USD], + Id: 0, + Pair: constants.BtcUsdPair, + MinPriceChangePpm: 1, }, { - Id: 1, - Pair: constants.EthUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_ETH_USD], + Id: 1, + Pair: constants.EthUsdPair, + MinPriceChangePpm: 1, }, }, MarketPrices: []types.MarketPrice{ @@ -136,18 +102,14 @@ func TestGenesisState_Validate(t *testing.T) { genState: &types.GenesisState{ MarketParams: []types.MarketParam{ { - Id: 0, - Pair: constants.BtcUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_BTC_USD], + Id: 0, + Pair: constants.BtcUsdPair, + MinPriceChangePpm: 1, }, { - Id: 1, - Pair: constants.EthUsdPair, - MinExchanges: 1, - MinPriceChangePpm: 1, - ExchangeConfigJson: constants.TestMarketExchangeConfigs[exchange_config.MARKET_ETH_USD], + Id: 1, + Pair: constants.EthUsdPair, + MinPriceChangePpm: 1, }, }, MarketPrices: []types.MarketPrice{ diff --git a/protocol/x/prices/types/market_param.go b/protocol/x/prices/types/market_param.go index 918f47fe99..259b60111e 100644 --- a/protocol/x/prices/types/market_param.go +++ b/protocol/x/prices/types/market_param.go @@ -3,7 +3,6 @@ package types import ( errorsmod "cosmossdk.io/errors" "github.com/dydxprotocol/v4-chain/protocol/lib" - "github.com/dydxprotocol/v4-chain/protocol/lib/json" ) // Validate checks that the MarketParam is valid. @@ -13,10 +12,6 @@ func (mp *MarketParam) Validate() error { return errorsmod.Wrap(ErrInvalidInput, "Pair cannot be empty") } - if mp.MinExchanges == 0 { - return ErrZeroMinExchanges - } - // Validate min price change. if mp.MinPriceChangePpm == 0 || mp.MinPriceChangePpm >= lib.MaxPriceChangePpm { return errorsmod.Wrapf( @@ -25,14 +20,5 @@ func (mp *MarketParam) Validate() error { lib.MaxPriceChangePpm) } - if err := json.IsValidJSON(mp.ExchangeConfigJson); err != nil { - return errorsmod.Wrapf( - ErrInvalidInput, - "ExchangeConfigJson string is not valid: err=%v, input=%v", - err, - mp.ExchangeConfigJson, - ) - } - return nil } diff --git a/protocol/x/prices/types/market_param.pb.go b/protocol/x/prices/types/market_param.pb.go index 4dbfd10c4f..5d9deda33d 100644 --- a/protocol/x/prices/types/market_param.pb.go +++ b/protocol/x/prices/types/market_param.pb.go @@ -36,16 +36,20 @@ type MarketParam struct { // represents “$10,000`. Therefore `10 ^ Exponent` represents the smallest // price step (in dollars) that can be recorded. // - // Deprecated since v7.1.x. This value is now determined from the marketmap. + // Deprecated since v8.x. This value is now determined from the marketmap. Exponent int32 `protobuf:"zigzag32,3,opt,name=exponent,proto3" json:"exponent,omitempty"` // Deprecated: Do not use. // The minimum number of exchanges that should be reporting a live price for // a price update to be considered valid. + // + // Deprecated since v8.x. This value is now determined from the marketmap. MinExchanges uint32 `protobuf:"varint,4,opt,name=min_exchanges,json=minExchanges,proto3" json:"min_exchanges,omitempty"` // The minimum allowable change in `price` value that would cause a price // update on the network. Measured as `1e-6` (parts per million). MinPriceChangePpm uint32 `protobuf:"varint,5,opt,name=min_price_change_ppm,json=minPriceChangePpm,proto3" json:"min_price_change_ppm,omitempty"` // A string of json that encodes the configuration for resolving the price // of this market on various exchanges. + // + // Deprecated since v8.x. This is now determined from the marketmap. ExchangeConfigJson string `protobuf:"bytes,6,opt,name=exchange_config_json,json=exchangeConfigJson,proto3" json:"exchange_config_json,omitempty"` } diff --git a/protocol/x/prices/types/market_param_test.go b/protocol/x/prices/types/market_param_test.go index 75f5d0a5d1..1b0b9811e6 100644 --- a/protocol/x/prices/types/market_param_test.go +++ b/protocol/x/prices/types/market_param_test.go @@ -8,7 +8,6 @@ import ( ) func TestMarketParam_Validate(t *testing.T) { - validExchangeConfigJson := `{"exchanges":[{"exchangeName":"Binance","ticker":"BTCUSDT"}]}` testCases := []struct { name string input types.MarketParam @@ -17,53 +16,27 @@ func TestMarketParam_Validate(t *testing.T) { { name: "Valid MarketParam", input: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "BTC-USD", + MinPriceChangePpm: 1_000, }, expErrMsg: "", }, { name: "Empty pair", input: types.MarketParam{ - Pair: "", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "", + MinPriceChangePpm: 1_000, }, expErrMsg: "Pair cannot be empty", }, { name: "Invalid MinPriceChangePpm", input: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 0, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "BTC-USD", + MinPriceChangePpm: 0, }, expErrMsg: "Min price change in parts-per-million must be greater than 0", }, - { - name: "Empty ExchangeConfigJson", - input: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: "", - }, - expErrMsg: "ExchangeConfigJson string is not valid", - }, - { - name: "Typo in ExchangeConfigJson", - input: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: `{"exchanges":[]`, // missing a bracket - }, - expErrMsg: "ExchangeConfigJson string is not valid", - }, } for _, tc := range testCases { diff --git a/protocol/x/prices/types/message_create_oracle_market_test.go b/protocol/x/prices/types/message_create_oracle_market_test.go index 903cadc28d..6af6c6b7fa 100644 --- a/protocol/x/prices/types/message_create_oracle_market_test.go +++ b/protocol/x/prices/types/message_create_oracle_market_test.go @@ -1,15 +1,15 @@ package types_test import ( - "github.com/dydxprotocol/v4-chain/protocol/x/prices/client/testutil" "testing" + "github.com/dydxprotocol/v4-chain/protocol/x/prices/client/testutil" + types "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" "github.com/stretchr/testify/require" ) func TestMsgCreateOracleMarket_ValidateBasic(t *testing.T) { - validExchangeConfigJson := `{"exchanges":[{"exchangeName":"Binance","ticker":"BTCUSDT"}]}` tests := []struct { desc string msg types.MsgCreateOracleMarket @@ -36,10 +36,8 @@ func TestMsgCreateOracleMarket_ValidateBasic(t *testing.T) { msg: types.MsgCreateOracleMarket{ Authority: testutil.ValidAuthority, Params: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "BTC-USD", + MinPriceChangePpm: 1_000, }, }, expectedErr: "", @@ -49,10 +47,8 @@ func TestMsgCreateOracleMarket_ValidateBasic(t *testing.T) { msg: types.MsgCreateOracleMarket{ Authority: testutil.ValidAuthority, Params: types.MarketParam{ - Pair: "", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "", + MinPriceChangePpm: 1_000, }, }, expectedErr: "Pair cannot be empty", @@ -62,40 +58,12 @@ func TestMsgCreateOracleMarket_ValidateBasic(t *testing.T) { msg: types.MsgCreateOracleMarket{ Authority: testutil.ValidAuthority, Params: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 0, - ExchangeConfigJson: validExchangeConfigJson, + Pair: "BTC-USD", + MinPriceChangePpm: 0, }, }, expectedErr: "Min price change in parts-per-million must be greater than 0", }, - { - desc: "Empty ExchangeConfigJson", - msg: types.MsgCreateOracleMarket{ - Authority: testutil.ValidAuthority, - Params: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: "", - }, - }, - expectedErr: "ExchangeConfigJson string is not valid", - }, - { - desc: "Typo in ExchangeConfigJson", - msg: types.MsgCreateOracleMarket{ - Authority: testutil.ValidAuthority, - Params: types.MarketParam{ - Pair: "BTC-USD", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: `{"exchanges":[]`, // missing a bracket - }, - }, - expectedErr: "ExchangeConfigJson string is not valid", - }, } for _, tc := range tests { diff --git a/protocol/x/prices/types/message_update_market_param_test.go b/protocol/x/prices/types/message_update_market_param_test.go index d2dda7dd21..d13c5fee0e 100644 --- a/protocol/x/prices/types/message_update_market_param_test.go +++ b/protocol/x/prices/types/message_update_market_param_test.go @@ -1,9 +1,10 @@ package types_test import ( - "github.com/dydxprotocol/v4-chain/protocol/x/prices/client/testutil" "testing" + "github.com/dydxprotocol/v4-chain/protocol/x/prices/client/testutil" + "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" "github.com/stretchr/testify/require" ) @@ -17,10 +18,8 @@ func TestMsgUpdateMarketParam_ValidateBasic(t *testing.T) { msg: types.MsgUpdateMarketParam{ Authority: testutil.ValidAuthority, MarketParam: types.MarketParam{ - Pair: "test", - MinExchanges: 1, - MinPriceChangePpm: 1_000, - ExchangeConfigJson: "{}", + Pair: "test", + MinPriceChangePpm: 1_000, }, }, }, @@ -43,29 +42,16 @@ func TestMsgUpdateMarketParam_ValidateBasic(t *testing.T) { Authority: testutil.ValidAuthority, MarketParam: types.MarketParam{ Pair: "", - MinExchanges: 1, MinPriceChangePpm: 1_000, }, }, expectedErr: "Pair cannot be empty", }, - "Failure: 0 MinExchanges": { - msg: types.MsgUpdateMarketParam{ - Authority: testutil.ValidAuthority, - MarketParam: types.MarketParam{ - Pair: "test", - MinExchanges: 0, - MinPriceChangePpm: 1_000, - }, - }, - expectedErr: "Min exchanges must be greater than zero", - }, "Failure: 0 MinPriceChangePpm": { msg: types.MsgUpdateMarketParam{ Authority: testutil.ValidAuthority, MarketParam: types.MarketParam{ Pair: "test", - MinExchanges: 2, MinPriceChangePpm: 0, }, }, @@ -76,7 +62,6 @@ func TestMsgUpdateMarketParam_ValidateBasic(t *testing.T) { Authority: testutil.ValidAuthority, MarketParam: types.MarketParam{ Pair: "test", - MinExchanges: 2, MinPriceChangePpm: 10_000, }, }, From 1010960d68f33cd137289f06266c7a434d89aaca Mon Sep 17 00:00:00 2001 From: Jonathan Fung <121899091+jonfung-dydx@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:14:36 -0400 Subject: [PATCH 103/120] Full node streaming -- perp position to signed int (#2544) --- .../dydxprotocol/subaccounts/streaming.ts | 12 ++-- .../dydxprotocol/subaccounts/streaming.proto | 4 +- protocol/x/subaccounts/keeper/subaccount.go | 4 +- protocol/x/subaccounts/types/streaming.pb.go | 56 +++++++++---------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/streaming.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/streaming.ts index fd54ef914b..ce7dc7b83c 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/streaming.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/streaming.ts @@ -59,7 +59,7 @@ export interface StreamSubaccountUpdateSDKType { export interface SubaccountPerpetualPosition { /** The `Id` of the `Perpetual`. */ perpetualId: number; - /** The size of the position in base quantums. */ + /** The size of the position in base quantums. Negative means short. */ quantums: Long; } @@ -71,7 +71,7 @@ export interface SubaccountPerpetualPosition { export interface SubaccountPerpetualPositionSDKType { /** The `Id` of the `Perpetual`. */ perpetual_id: number; - /** The size of the position in base quantums. */ + /** The size of the position in base quantums. Negative means short. */ quantums: Long; } @@ -178,7 +178,7 @@ export const StreamSubaccountUpdate = { function createBaseSubaccountPerpetualPosition(): SubaccountPerpetualPosition { return { perpetualId: 0, - quantums: Long.UZERO + quantums: Long.ZERO }; } @@ -189,7 +189,7 @@ export const SubaccountPerpetualPosition = { } if (!message.quantums.isZero()) { - writer.uint32(16).uint64(message.quantums); + writer.uint32(16).int64(message.quantums); } return writer; @@ -209,7 +209,7 @@ export const SubaccountPerpetualPosition = { break; case 2: - message.quantums = (reader.uint64() as Long); + message.quantums = (reader.int64() as Long); break; default: @@ -224,7 +224,7 @@ export const SubaccountPerpetualPosition = { fromPartial(object: DeepPartial): SubaccountPerpetualPosition { const message = createBaseSubaccountPerpetualPosition(); message.perpetualId = object.perpetualId ?? 0; - message.quantums = object.quantums !== undefined && object.quantums !== null ? Long.fromValue(object.quantums) : Long.UZERO; + message.quantums = object.quantums !== undefined && object.quantums !== null ? Long.fromValue(object.quantums) : Long.ZERO; return message; } diff --git a/proto/dydxprotocol/subaccounts/streaming.proto b/proto/dydxprotocol/subaccounts/streaming.proto index 13b71ee1ae..9351391008 100644 --- a/proto/dydxprotocol/subaccounts/streaming.proto +++ b/proto/dydxprotocol/subaccounts/streaming.proto @@ -28,8 +28,8 @@ message StreamSubaccountUpdate { message SubaccountPerpetualPosition { // The `Id` of the `Perpetual`. uint32 perpetual_id = 1; - // The size of the position in base quantums. - uint64 quantums = 2; + // The size of the position in base quantums. Negative means short. + int64 quantums = 2; } // SubaccountAssetPosition provides information on a subaccount's updated asset diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index 52d4c05bb3..a047d9e2c9 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -150,7 +150,7 @@ func (k Keeper) GetStreamSubaccountUpdate( for i, pp := range subaccount.PerpetualPositions { perpetualPositions[i] = &types.SubaccountPerpetualPosition{ PerpetualId: pp.PerpetualId, - Quantums: pp.Quantums.BigInt().Uint64(), + Quantums: pp.Quantums.BigInt().Int64(), } } @@ -298,7 +298,7 @@ func GenerateStreamSubaccountUpdate( for i, pp := range updatedPerpetualPositions { perpetualPositions[i] = &types.SubaccountPerpetualPosition{ PerpetualId: pp.PerpetualId, - Quantums: pp.Quantums.BigInt().Uint64(), + Quantums: pp.Quantums.BigInt().Int64(), } } diff --git a/protocol/x/subaccounts/types/streaming.pb.go b/protocol/x/subaccounts/types/streaming.pb.go index 2babfbf862..68f50b9668 100644 --- a/protocol/x/subaccounts/types/streaming.pb.go +++ b/protocol/x/subaccounts/types/streaming.pb.go @@ -106,8 +106,8 @@ func (m *StreamSubaccountUpdate) GetSnapshot() bool { type SubaccountPerpetualPosition struct { // The `Id` of the `Perpetual`. PerpetualId uint32 `protobuf:"varint,1,opt,name=perpetual_id,json=perpetualId,proto3" json:"perpetual_id,omitempty"` - // The size of the position in base quantums. - Quantums uint64 `protobuf:"varint,2,opt,name=quantums,proto3" json:"quantums,omitempty"` + // The size of the position in base quantums. Negative means short. + Quantums int64 `protobuf:"varint,2,opt,name=quantums,proto3" json:"quantums,omitempty"` } func (m *SubaccountPerpetualPosition) Reset() { *m = SubaccountPerpetualPosition{} } @@ -150,7 +150,7 @@ func (m *SubaccountPerpetualPosition) GetPerpetualId() uint32 { return 0 } -func (m *SubaccountPerpetualPosition) GetQuantums() uint64 { +func (m *SubaccountPerpetualPosition) GetQuantums() int64 { if m != nil { return m.Quantums } @@ -224,30 +224,30 @@ func init() { } var fileDescriptor_e6cf3092946c3c13 = []byte{ - // 353 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xc1, 0x6a, 0xea, 0x40, - 0x14, 0x86, 0x1d, 0x95, 0x7b, 0x65, 0xd4, 0xcd, 0xc0, 0xbd, 0x46, 0x85, 0x60, 0x5d, 0x94, 0x74, - 0xd1, 0x84, 0xda, 0x76, 0xd9, 0x45, 0xbb, 0x93, 0x6e, 0x24, 0x52, 0x0a, 0xa5, 0x20, 0x63, 0x26, - 0xe8, 0x80, 0x66, 0xa6, 0x9e, 0x99, 0xa2, 0x6f, 0xd1, 0xc7, 0xea, 0xd2, 0x65, 0x97, 0xc5, 0xbc, - 0x48, 0x31, 0xc6, 0x31, 0x52, 0x14, 0x77, 0xf9, 0xcf, 0x7f, 0xce, 0xf7, 0x67, 0x0e, 0x07, 0x3b, - 0x6c, 0xc1, 0xe6, 0x72, 0x26, 0x94, 0x08, 0xc4, 0xc4, 0x03, 0x3d, 0xa4, 0x41, 0x20, 0x74, 0xa4, - 0xc0, 0x03, 0x35, 0x0b, 0xe9, 0x94, 0x47, 0x23, 0x37, 0xb1, 0x89, 0x95, 0xed, 0x74, 0x33, 0x9d, - 0x8d, 0x8b, 0xc3, 0x0c, 0xf3, 0xbd, 0x81, 0xb4, 0xe3, 0x3c, 0xfe, 0xdf, 0x4f, 0xc0, 0x7d, 0x63, - 0x3d, 0x49, 0x46, 0x55, 0x48, 0x1e, 0x71, 0x75, 0xd7, 0x3e, 0xe0, 0xcc, 0x42, 0x2d, 0xe4, 0x94, - 0x3b, 0xe7, 0xee, 0xa1, 0x5c, 0x77, 0x87, 0xe8, 0x32, 0xbf, 0x02, 0x19, 0x45, 0x34, 0x6e, 0xea, - 0x04, 0xcb, 0x06, 0x32, 0x9c, 0xc9, 0x50, 0x69, 0x3a, 0x19, 0x48, 0x01, 0x5c, 0x71, 0x11, 0x81, - 0x95, 0x6f, 0x15, 0x9c, 0x72, 0xe7, 0xf6, 0x14, 0x74, 0x6f, 0x3b, 0xde, 0x4b, 0xa7, 0xfd, 0x7a, - 0x4a, 0xfe, 0xe5, 0x00, 0xe1, 0xb8, 0xb6, 0x8d, 0xa5, 0x00, 0xa1, 0xca, 0x44, 0x16, 0x92, 0xc8, - 0xab, 0x53, 0x22, 0xef, 0xd7, 0xa3, 0x26, 0xee, 0x5f, 0x4a, 0xdc, 0xab, 0x02, 0x69, 0xe0, 0x12, - 0x44, 0x54, 0xc2, 0x58, 0x28, 0xab, 0xd8, 0x42, 0x4e, 0xc9, 0x37, 0xba, 0xfd, 0x8a, 0x9b, 0x47, - 0x1e, 0x40, 0xce, 0x70, 0x65, 0xb7, 0x94, 0x74, 0xd1, 0x55, 0xbf, 0x6c, 0x6a, 0x5d, 0xb6, 0xa6, - 0xbf, 0x69, 0x1a, 0x29, 0x3d, 0x5d, 0x2f, 0x0b, 0x39, 0x45, 0xdf, 0xe8, 0x76, 0x0f, 0xd7, 0x0e, - 0xfc, 0x2b, 0xa9, 0xe3, 0xd2, 0xe6, 0xdd, 0x86, 0xfa, 0x37, 0xd1, 0xc7, 0x89, 0x0f, 0xcf, 0x9f, - 0x2b, 0x1b, 0x2d, 0x57, 0x36, 0xfa, 0x5e, 0xd9, 0xe8, 0x23, 0xb6, 0x73, 0xcb, 0xd8, 0xce, 0x7d, - 0xc5, 0x76, 0xee, 0xe5, 0x6e, 0xc4, 0xd5, 0x58, 0x0f, 0xdd, 0x40, 0x4c, 0xbd, 0xbd, 0x2b, 0x7b, - 0xbf, 0xb9, 0x0c, 0xc6, 0x94, 0x47, 0x9e, 0xa9, 0xcc, 0xf7, 0x2e, 0x4f, 0x2d, 0x64, 0x08, 0xc3, - 0x3f, 0x89, 0x7b, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x34, 0x6c, 0x66, 0xe6, 0x02, 0x00, - 0x00, + // 354 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xc1, 0x4e, 0xc2, 0x40, + 0x10, 0x86, 0x29, 0x10, 0x25, 0x0b, 0x5c, 0x36, 0x51, 0x0a, 0x24, 0x0d, 0x72, 0x30, 0xf5, 0x60, + 0x1b, 0x51, 0x8f, 0x1e, 0xf4, 0x46, 0xbc, 0x90, 0x12, 0x63, 0x62, 0x4c, 0xc8, 0xd2, 0x6d, 0x60, + 0x13, 0xe8, 0xae, 0xcc, 0xae, 0x81, 0xb7, 0xf0, 0xb1, 0x3c, 0x72, 0xf4, 0x68, 0xe8, 0x8b, 0x18, + 0x4a, 0xd9, 0x96, 0x28, 0x86, 0x5b, 0xff, 0xf9, 0x67, 0xbe, 0xbf, 0x3b, 0x19, 0x64, 0xd3, 0x05, + 0x9d, 0x8b, 0x19, 0x97, 0xdc, 0xe7, 0x13, 0x17, 0xd4, 0x90, 0xf8, 0x3e, 0x57, 0xa1, 0x04, 0x17, + 0xe4, 0x2c, 0x20, 0x53, 0x16, 0x8e, 0x9c, 0xd8, 0xc6, 0x66, 0xb6, 0xd3, 0xc9, 0x74, 0x36, 0x2e, + 0xf6, 0x33, 0xf4, 0xf7, 0x06, 0xd2, 0x8e, 0xf2, 0xe8, 0xb4, 0x1f, 0x83, 0xfb, 0xda, 0x7a, 0x12, + 0x94, 0xc8, 0x00, 0x3f, 0xa2, 0x6a, 0xda, 0x3e, 0x60, 0xd4, 0x34, 0x5a, 0x86, 0x5d, 0xee, 0x9c, + 0x3b, 0xfb, 0x72, 0x9d, 0x14, 0xd1, 0xa5, 0x5e, 0x05, 0x32, 0x0a, 0x2b, 0xd4, 0x54, 0x31, 0x96, + 0x0e, 0x44, 0x30, 0x13, 0x81, 0x54, 0x64, 0x32, 0x10, 0x1c, 0x98, 0x64, 0x3c, 0x04, 0x33, 0xdf, + 0x2a, 0xd8, 0xe5, 0xce, 0xed, 0x21, 0xe8, 0xde, 0x76, 0xbc, 0x97, 0x4c, 0x7b, 0xf5, 0x84, 0xfc, + 0xcb, 0x01, 0xcc, 0x50, 0x6d, 0x1b, 0x4b, 0x00, 0x02, 0x99, 0x89, 0x2c, 0xc4, 0x91, 0x57, 0x87, + 0x44, 0xde, 0xaf, 0x47, 0x75, 0xdc, 0x49, 0x42, 0xdc, 0xa9, 0x02, 0x6e, 0xa0, 0x12, 0x84, 0x44, + 0xc0, 0x98, 0x4b, 0xb3, 0xd8, 0x32, 0xec, 0x92, 0xa7, 0x75, 0xfb, 0x15, 0x35, 0xff, 0x79, 0x00, + 0x3e, 0x43, 0x95, 0x74, 0x29, 0xc9, 0xa2, 0xab, 0x5e, 0x59, 0xd7, 0xba, 0x74, 0x4d, 0x7f, 0x53, + 0x24, 0x94, 0x6a, 0xba, 0x5e, 0x96, 0x61, 0x17, 0x3c, 0xad, 0xdb, 0x3d, 0x54, 0xdb, 0xf3, 0xaf, + 0xb8, 0x8e, 0x4a, 0x9b, 0x77, 0x6b, 0xea, 0x71, 0xac, 0xff, 0x20, 0x16, 0x53, 0xe2, 0xc3, 0xf3, + 0xe7, 0xca, 0x32, 0x96, 0x2b, 0xcb, 0xf8, 0x5e, 0x59, 0xc6, 0x47, 0x64, 0xe5, 0x96, 0x91, 0x95, + 0xfb, 0x8a, 0xac, 0xdc, 0xcb, 0xdd, 0x88, 0xc9, 0xb1, 0x1a, 0x3a, 0x3e, 0x9f, 0xba, 0x3b, 0x57, + 0xf6, 0x7e, 0x73, 0xe9, 0x8f, 0x09, 0x0b, 0x5d, 0x5d, 0x99, 0xef, 0x5c, 0x9e, 0x5c, 0x88, 0x00, + 0x86, 0x47, 0xb1, 0x7b, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x00, 0x93, 0x3a, 0xe6, 0x02, + 0x00, 0x00, } func (m *StreamSubaccountUpdate) Marshal() (dAtA []byte, err error) { @@ -700,7 +700,7 @@ func (m *SubaccountPerpetualPosition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Quantums |= uint64(b&0x7F) << shift + m.Quantums |= int64(b&0x7F) << shift if b < 0x80 { break } From cdceacf253e5c5dcc843b46c2c527c14ea935459 Mon Sep 17 00:00:00 2001 From: jerryfan01234 <44346807+jerryfan01234@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:00:04 -0400 Subject: [PATCH 104/120] [OTE-882] Add prefix to accountplus keeper (#2526) --- .../upgrades/v8.0/migrate_accountplus_test.go | 81 +++++++++++++++++++ protocol/app/upgrades/v8.0/upgrade.go | 63 +++++++++++++++ protocol/x/accountplus/keeper/keeper.go | 43 +++++----- protocol/x/accountplus/keeper/keeper_test.go | 50 ++++++++++++ .../x/accountplus/keeper/timestampnonce.go | 11 +-- protocol/x/accountplus/types/keys.go | 5 ++ 6 files changed, 226 insertions(+), 27 deletions(-) create mode 100644 protocol/app/upgrades/v8.0/migrate_accountplus_test.go create mode 100644 protocol/app/upgrades/v8.0/upgrade.go diff --git a/protocol/app/upgrades/v8.0/migrate_accountplus_test.go b/protocol/app/upgrades/v8.0/migrate_accountplus_test.go new file mode 100644 index 0000000000..88be8a4994 --- /dev/null +++ b/protocol/app/upgrades/v8.0/migrate_accountplus_test.go @@ -0,0 +1,81 @@ +package v_8_0 + +import ( + "testing" + + "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + accountplustypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" + "github.com/stretchr/testify/suite" +) + +type UpgradeTestSuite struct { + suite.Suite + + tApp *testapp.TestApp + Ctx sdk.Context +} + +func TestMigrateAccountplusAccountState(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +func (s *UpgradeTestSuite) SetupTest() { + s.tApp = testapp.NewTestAppBuilder(s.T()).Build() + s.Ctx = s.tApp.InitChain() +} + +func (s *UpgradeTestSuite) TestUpgrade_MigrateAccountplusAccountState() { + ctx := s.Ctx + store := ctx.KVStore(s.tApp.App.AccountPlusKeeper.GetStoreKey()) + prefixStore := prefix.NewStore(store, []byte(accountplustypes.AccountStateKeyPrefix)) + + // Create some AccountState with no prefixes + addresses := []string{"address1", "address2", "address3"} + for _, addr := range addresses { + accAddress := sdk.AccAddress([]byte(addr)) + accountState := accountplustypes.AccountState{ + Address: addr, + TimestampNonceDetails: accountplustypes.TimestampNonceDetails{ + TimestampNonces: []uint64{1, 2, 3}, + MaxEjectedNonce: 0, + }, + } + bz := s.tApp.App.AccountPlusKeeper.GetCdc().MustMarshal(&accountState) + store.Set(accAddress, bz) + } + + // Verify unprefixed keys were successfully created + for _, addr := range addresses { + accAddress := sdk.AccAddress([]byte(addr)) + bz := store.Get(accAddress) + s.Require().NotNil(bz, "Unprefixed key not created for %s", addr) + } + + // Migrate + migrateAccountplusAccountState(ctx, s.tApp.App.AccountPlusKeeper) + + // Verify that unprefixed keys are deleted and prefixed keys exist + for _, addr := range addresses { + accAddress := sdk.AccAddress([]byte(addr)) + + // Check that the old key no longer exists + bzOld := store.Get(accAddress) + s.Require().Nil(bzOld, "Unprefixed AccountState should be deleted for %s", addr) + + // Check that the new prefixed key exists + bzNew := prefixStore.Get(accAddress) + var actualAccountState accountplustypes.AccountState + s.tApp.App.AccountPlusKeeper.GetCdc().MustUnmarshal(bzNew, &actualAccountState) + expectedAccountState := accountplustypes.AccountState{ + Address: addr, + TimestampNonceDetails: accountplustypes.TimestampNonceDetails{ + TimestampNonces: []uint64{1, 2, 3}, + MaxEjectedNonce: 0, + }, + } + s.Require().NotNil(bzNew, "Prefixed AccountState should exist for %s", addr) + s.Require().Equal(expectedAccountState, actualAccountState, "Incorrect AccountState after migration for %s", addr) + } +} diff --git a/protocol/app/upgrades/v8.0/upgrade.go b/protocol/app/upgrades/v8.0/upgrade.go new file mode 100644 index 0000000000..12707b727b --- /dev/null +++ b/protocol/app/upgrades/v8.0/upgrade.go @@ -0,0 +1,63 @@ +package v_8_0 + +import ( + "bytes" + "fmt" + + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + accountpluskeeper "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper" + accountplustypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" +) + +// Migrate accountplus AccountState in kvstore from non-prefixed keys to prefixed keys +func migrateAccountplusAccountState(ctx sdk.Context, k accountpluskeeper.Keeper) { + ctx.Logger().Info("Migrating accountplus module AccountState in kvstore from non-prefixed keys to prefixed keys") + + store := ctx.KVStore(k.GetStoreKey()) + + // Iterate on unprefixed keys + iterator := storetypes.KVStorePrefixIterator(store, nil) + defer iterator.Close() + + var keysToDelete [][]byte + var accountStatesToSet []struct { + address sdk.AccAddress + accountState accountplustypes.AccountState + } + for ; iterator.Valid(); iterator.Next() { + key := iterator.Key() + + // Double check that key does not have prefix + if bytes.HasPrefix(key, []byte(accountplustypes.AccountStateKeyPrefix)) { + panic(fmt.Sprintf("unexpected key with prefix %X found during migration", accountplustypes.AccountStateKeyPrefix)) + } + + value := iterator.Value() + var accountState accountplustypes.AccountState + if err := k.GetCdc().Unmarshal(value, &accountState); err != nil { + panic(fmt.Sprintf("failed to unmarshal AccountState for key %X: %s", key, err)) + } + + accountStatesToSet = append(accountStatesToSet, struct { + address sdk.AccAddress + accountState accountplustypes.AccountState + }{key, accountState}) + + keysToDelete = append(keysToDelete, key) + } + + // Set prefixed keys + for _, item := range accountStatesToSet { + k.SetAccountState(ctx, item.address, item.accountState) + } + + // Delete unprefixed keys + for _, key := range keysToDelete { + store.Delete(key) + } + + ctx.Logger().Info("Successfully migrated accountplus AccountState keys") +} + +// TODO: Scaffolding for upgrade: https://linear.app/dydx/issue/OTE-886/v8-upgrade-handler-scaffold diff --git a/protocol/x/accountplus/keeper/keeper.go b/protocol/x/accountplus/keeper/keeper.go index d63297e19f..b09d435d82 100644 --- a/protocol/x/accountplus/keeper/keeper.go +++ b/protocol/x/accountplus/keeper/keeper.go @@ -1,12 +1,11 @@ package keeper import ( - "bytes" - "errors" "fmt" "strings" "cosmossdk.io/log" + "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -38,6 +37,14 @@ func NewKeeper( } } +func (k Keeper) GetStoreKey() storetypes.StoreKey { + return k.storeKey +} + +func (k Keeper) GetCdc() codec.BinaryCodec { + return k.cdc +} + func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With(log.ModuleKey, fmt.Sprintf("x/%s", types.ModuleName)) } @@ -46,26 +53,22 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) InitializeForGenesis(ctx sdk.Context) { } -// Get all account details pairs in store +// Get all AccountStates from kvstore func (k Keeper) GetAllAccountStates(ctx sdk.Context) ([]types.AccountState, error) { - store := ctx.KVStore(k.storeKey) - - iterator := storetypes.KVStorePrefixIterator(store, nil) + iterator := storetypes.KVStorePrefixIterator( + ctx.KVStore(k.storeKey), + []byte(types.AccountStateKeyPrefix), + ) defer iterator.Close() accounts := []types.AccountState{} for ; iterator.Valid(); iterator.Next() { - key := iterator.Key() - - // Temporary workaround to exclude smart account kv pairs. - if bytes.HasPrefix(key, []byte(types.SmartAccountKeyPrefix)) { - continue + var accountState types.AccountState + err := k.cdc.Unmarshal(iterator.Value(), &accountState) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal account state: %w", err) } - accountState, found := k.GetAccountState(ctx, key) - if !found { - return accounts, errors.New("Could not get account state for address: " + sdk.AccAddress(iterator.Key()).String()) - } accounts = append(accounts, accountState) } @@ -144,7 +147,7 @@ func (k Keeper) GetAllAuthenticatorData(ctx sdk.Context) ([]types.AuthenticatorD return accountAuthenticators, nil } -func GetAccountPlusStateWithTimestampNonceDetails( +func AccountStateFromTimestampNonceDetails( address sdk.AccAddress, tsNonce uint64, ) types.AccountState { @@ -162,8 +165,8 @@ func (k Keeper) GetAccountState( ctx sdk.Context, address sdk.AccAddress, ) (types.AccountState, bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(address.Bytes()) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AccountStateKeyPrefix)) + bz := prefixStore.Get(address.Bytes()) if bz == nil { return types.AccountState{}, false } @@ -185,9 +188,9 @@ func (k Keeper) SetAccountState( address sdk.AccAddress, accountState types.AccountState, ) { - store := ctx.KVStore(k.storeKey) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AccountStateKeyPrefix)) bz := k.cdc.MustMarshal(&accountState) - store.Set(address.Bytes(), bz) + prefixStore.Set(address.Bytes(), bz) } func (k Keeper) HasAuthority(authority string) bool { diff --git a/protocol/x/accountplus/keeper/keeper_test.go b/protocol/x/accountplus/keeper/keeper_test.go index bb0d2d0bbb..58e0101c66 100644 --- a/protocol/x/accountplus/keeper/keeper_test.go +++ b/protocol/x/accountplus/keeper/keeper_test.go @@ -53,6 +53,56 @@ func (s *KeeperTestSuite) SetupTest() { ) } +func (s *KeeperTestSuite) TestKeeper_Set_Get_GetAllAccountState() { + ctx := s.Ctx + + accountState1 := types.AccountState{ + Address: "address1", + TimestampNonceDetails: types.TimestampNonceDetails{ + TimestampNonces: []uint64{1, 2, 3}, + MaxEjectedNonce: 0, + }, + } + + accountState2 := types.AccountState{ + Address: "address2", + TimestampNonceDetails: types.TimestampNonceDetails{ + TimestampNonces: []uint64{1, 2, 3}, + MaxEjectedNonce: 0, + }, + } + + // SetAccountState + s.tApp.App.AccountPlusKeeper.SetAccountState( + ctx, + sdk.AccAddress([]byte(accountState1.Address)), + accountState1, + ) + + // GetAccountState + _, found := s.tApp.App.AccountPlusKeeper.GetAccountState(ctx, sdk.AccAddress([]byte(accountState1.Address))) + s.Require().True(found, "Account state not found") + + // GetAllAccountStates + accountStates, err := s.tApp.App.AccountPlusKeeper.GetAllAccountStates(ctx) + s.Require().NoError(err, "Should not error when getting all account states") + s.Require().Equal(len(accountStates), 1, "Incorrect number of AccountStates retrieved") + s.Require().Equal(accountStates[0], accountState1, "Incorrect AccountState retrieved") + + // Add one more AccountState and check GetAllAccountStates + s.tApp.App.AccountPlusKeeper.SetAccountState( + ctx, + sdk.AccAddress([]byte(accountState2.Address)), + accountState2, + ) + + accountStates, err = s.tApp.App.AccountPlusKeeper.GetAllAccountStates(ctx) + s.Require().NoError(err, "Should not error when getting all account states") + s.Require().Equal(len(accountStates), 2, "Incorrect number of AccountStates retrieved") + s.Require().Contains(accountStates, accountState1, "Retrieved AccountStates does not contain accountState1") + s.Require().Contains(accountStates, accountState2, "Retrieved AccountStates does not contain accountState2") +} + func (s *KeeperTestSuite) TestKeeper_AddAuthenticator() { ctx := s.Ctx diff --git a/protocol/x/accountplus/keeper/timestampnonce.go b/protocol/x/accountplus/keeper/timestampnonce.go index e23a0196a6..dad8e25a16 100644 --- a/protocol/x/accountplus/keeper/timestampnonce.go +++ b/protocol/x/accountplus/keeper/timestampnonce.go @@ -41,7 +41,7 @@ func (k Keeper) ProcessTimestampNonce(ctx sdk.Context, acc sdk.AccountI, tsNonce accountState, found := k.GetAccountState(ctx, address) if !found { // initialize accountplus state with ts nonce details - k.SetAccountState(ctx, address, GetAccountPlusStateWithTimestampNonceDetails(address, tsNonce)) + k.SetAccountState(ctx, address, AccountStateFromTimestampNonceDetails(address, tsNonce)) } else { EjectStaleTimestampNonces(&accountState, blockTs) tsNonceAccepted := AttemptTimestampNonceUpdate(tsNonce, &accountState) @@ -56,9 +56,10 @@ func (k Keeper) ProcessTimestampNonce(ctx sdk.Context, acc sdk.AccountI, tsNonce // Inplace eject all stale timestamps. func EjectStaleTimestampNonces(accountState *types.AccountState, referenceTs uint64) { tsNonceDetails := &accountState.TimestampNonceDetails + oldestAllowedTs := referenceTs - MaxTimeInPastMs var newTsNonces []uint64 for _, tsNonce := range tsNonceDetails.TimestampNonces { - if tsNonce >= referenceTs-MaxTimeInPastMs { + if tsNonce >= oldestAllowedTs { newTsNonces = append(newTsNonces, tsNonce) } else { if tsNonce > tsNonceDetails.MaxEjectedNonce { @@ -115,9 +116,5 @@ func isLargerThanSmallestValue(value uint64, values []uint64) (bool, int) { } } - if value > values[minIndex] { - return true, minIndex - } else { - return false, minIndex - } + return value > values[minIndex], minIndex } diff --git a/protocol/x/accountplus/types/keys.go b/protocol/x/accountplus/types/keys.go index 3844749bf3..2e0d0edd91 100644 --- a/protocol/x/accountplus/types/keys.go +++ b/protocol/x/accountplus/types/keys.go @@ -17,6 +17,11 @@ const ( StoreKey = ModuleName ) +// Prefix for account state. +const ( + AccountStateKeyPrefix = "AS/" +) + // Below key prefixes are for smart account implementation. const ( // SmartAccountKeyPrefix is the prefix key for all smart account store state. From 8237d2a3c6f98be0a59a7c8d4632d7782ddabf8c Mon Sep 17 00:00:00 2001 From: Tian Date: Thu, 31 Oct 2024 17:02:06 -0400 Subject: [PATCH 105/120] pass shares to withdraw in megavault withdrawal query rest endpoint (#2550) --- .../codegen/dydxprotocol/vault/query.lcd.ts | 18 +- proto/dydxprotocol/vault/query.proto | 6 +- protocol/x/vault/types/query.pb.go | 164 +++++++++--------- protocol/x/vault/types/query.pb.gw.go | 22 ++- 4 files changed, 97 insertions(+), 113 deletions(-) diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.lcd.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.lcd.ts index bde998565a..afae739e58 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.lcd.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/query.lcd.ts @@ -1,6 +1,6 @@ import { setPaginationParams } from "../../helpers"; import { LCDClient } from "@osmonauts/lcd"; -import { QueryParamsRequest, QueryParamsResponseSDKType, QueryVaultRequest, QueryVaultResponseSDKType, QueryAllVaultsRequest, QueryAllVaultsResponseSDKType, QueryMegavaultTotalSharesRequest, QueryMegavaultTotalSharesResponseSDKType, QueryMegavaultOwnerSharesRequest, QueryMegavaultOwnerSharesResponseSDKType, QueryMegavaultAllOwnerSharesRequest, QueryMegavaultAllOwnerSharesResponseSDKType, QueryVaultParamsRequest, QueryVaultParamsResponseSDKType, QueryMegavaultWithdrawalInfoRequest, QueryMegavaultWithdrawalInfoResponseSDKType } from "./query"; +import { QueryParamsRequest, QueryParamsResponseSDKType, QueryVaultRequest, QueryVaultResponseSDKType, QueryAllVaultsRequest, QueryAllVaultsResponseSDKType, QueryMegavaultTotalSharesRequest, QueryMegavaultTotalSharesResponseSDKType, QueryMegavaultOwnerSharesRequest, QueryMegavaultOwnerSharesResponseSDKType, QueryMegavaultAllOwnerSharesRequest, QueryMegavaultAllOwnerSharesResponseSDKType, QueryVaultParamsRequest, QueryVaultParamsResponseSDKType } from "./query"; export class LCDQueryClient { req: LCDClient; @@ -17,7 +17,6 @@ export class LCDQueryClient { this.megavaultOwnerShares = this.megavaultOwnerShares.bind(this); this.megavaultAllOwnerShares = this.megavaultAllOwnerShares.bind(this); this.vaultParams = this.vaultParams.bind(this); - this.megavaultWithdrawalInfo = this.megavaultWithdrawalInfo.bind(this); } /* Queries the Params. */ @@ -88,20 +87,5 @@ export class LCDQueryClient { const endpoint = `dydxprotocol/vault/params/${params.type}/${params.number}`; return await this.req.get(endpoint); } - /* Queries withdrawal info for megavault. */ - - - async megavaultWithdrawalInfo(params: QueryMegavaultWithdrawalInfoRequest): Promise { - const options: any = { - params: {} - }; - - if (typeof params?.sharesToWithdraw !== "undefined") { - options.params.shares_to_withdraw = params.sharesToWithdraw; - } - - const endpoint = `dydxprotocol/vault/megavault/withdrawal_info`; - return await this.req.get(endpoint, options); - } } \ No newline at end of file diff --git a/proto/dydxprotocol/vault/query.proto b/proto/dydxprotocol/vault/query.proto index ed82af2013..8436515739 100644 --- a/proto/dydxprotocol/vault/query.proto +++ b/proto/dydxprotocol/vault/query.proto @@ -51,8 +51,10 @@ service Query { // Queries withdrawal info for megavault. rpc MegavaultWithdrawalInfo(QueryMegavaultWithdrawalInfoRequest) returns (QueryMegavaultWithdrawalInfoResponse) { - option (google.api.http).get = - "/dydxprotocol/vault/megavault/withdrawal_info"; + option (google.api.http) = { + post : "/dydxprotocol/vault/megavault/withdrawal_info" + body : "*" + }; } } diff --git a/protocol/x/vault/types/query.pb.go b/protocol/x/vault/types/query.pb.go index 228db44453..c962a47aad 100644 --- a/protocol/x/vault/types/query.pb.go +++ b/protocol/x/vault/types/query.pb.go @@ -883,88 +883,88 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/vault/query.proto", fileDescriptor_478fb8dc0ff21ea6) } var fileDescriptor_478fb8dc0ff21ea6 = []byte{ - // 1282 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, - 0x17, 0xcf, 0xc6, 0x89, 0xfb, 0xcd, 0x4b, 0xd2, 0xf6, 0x3b, 0x49, 0x13, 0xd7, 0x2d, 0x4e, 0xb2, - 0x40, 0x9b, 0xa4, 0x8d, 0x97, 0xa4, 0x69, 0x8b, 0x44, 0x85, 0x9a, 0x20, 0x4a, 0x83, 0x04, 0xad, - 0x37, 0xa1, 0x48, 0x48, 0xb0, 0x8c, 0xbd, 0x13, 0x67, 0xc5, 0x7a, 0xc7, 0xd9, 0x9d, 0x4d, 0x62, - 0xa2, 0x48, 0x08, 0x89, 0x03, 0x37, 0x24, 0xae, 0x5c, 0xe0, 0x4f, 0x40, 0x48, 0x88, 0x03, 0x07, - 0x44, 0x25, 0x7a, 0xac, 0xe0, 0x82, 0x38, 0x54, 0x28, 0xe1, 0xcc, 0xdf, 0x80, 0x76, 0x66, 0xd6, - 0xde, 0x75, 0xd6, 0xce, 0xb6, 0x72, 0x2f, 0x91, 0x77, 0xe6, 0xbd, 0xcf, 0xfb, 0xbc, 0x37, 0xef, - 0x57, 0xa0, 0x60, 0x36, 0xcc, 0xbd, 0xba, 0x4b, 0x19, 0xad, 0x50, 0x5b, 0xdb, 0xc1, 0xbe, 0xcd, - 0xb4, 0x6d, 0x9f, 0xb8, 0x8d, 0x22, 0x3f, 0x44, 0x28, 0x7a, 0x5f, 0xe4, 0xf7, 0xf9, 0xf3, 0x15, - 0xea, 0xd5, 0xa8, 0x67, 0xf0, 0x63, 0x4d, 0x7c, 0x08, 0xf1, 0xfc, 0xbc, 0xf8, 0xd2, 0xca, 0xd8, - 0x23, 0x02, 0x47, 0xdb, 0x59, 0x2c, 0x13, 0x86, 0x17, 0xb5, 0x3a, 0xae, 0x5a, 0x0e, 0x66, 0x16, - 0x75, 0xa4, 0xec, 0x78, 0x95, 0x56, 0xa9, 0xc0, 0x08, 0x7e, 0xc9, 0xd3, 0x8b, 0x55, 0x4a, 0xab, - 0x36, 0xd1, 0x70, 0xdd, 0xd2, 0xb0, 0xe3, 0x50, 0xc6, 0x55, 0x42, 0xfc, 0xb9, 0x18, 0x5d, 0xcf, - 0x2f, 0xe3, 0x4a, 0x85, 0xfa, 0x0e, 0xf3, 0x22, 0xbf, 0xa5, 0xe8, 0x54, 0x82, 0x67, 0x75, 0xec, - 0xe2, 0x5a, 0x88, 0x95, 0xe4, 0xba, 0xb7, 0x85, 0x5d, 0xd2, 0xe5, 0x9e, 0xff, 0x15, 0xf7, 0xea, - 0x38, 0xa0, 0x52, 0xe0, 0xe1, 0x7d, 0x0e, 0xaa, 0x93, 0x6d, 0x9f, 0x78, 0x4c, 0xfd, 0x4d, 0x81, - 0xb1, 0xd8, 0xb1, 0x57, 0xa7, 0x8e, 0x47, 0xd0, 0x87, 0x30, 0x61, 0x92, 0xcd, 0x40, 0xdd, 0xd8, - 0xf6, 0x29, 0xb3, 0x9c, 0xaa, 0x21, 0xd8, 0xe4, 0x94, 0x69, 0x65, 0x76, 0x78, 0x69, 0xa6, 0x78, - 0x3c, 0xd2, 0xc5, 0x92, 0x90, 0x14, 0x50, 0xab, 0x03, 0x8f, 0x9e, 0x4c, 0xf5, 0xe9, 0xe3, 0x12, - 0x26, 0x76, 0x87, 0x4a, 0x70, 0x86, 0xd6, 0x89, 0x8b, 0x19, 0x75, 0x43, 0xdc, 0x7e, 0x8e, 0xab, - 0x26, 0xe1, 0xde, 0x93, 0xa2, 0x31, 0xe0, 0xd3, 0x34, 0x76, 0xaa, 0x7e, 0x04, 0xff, 0xe7, 0x8e, - 0x3c, 0x08, 0x54, 0xa4, 0x7b, 0x68, 0x11, 0x06, 0x58, 0xa3, 0x4e, 0x38, 0xe9, 0xd3, 0x4b, 0x2f, - 0x24, 0x81, 0x73, 0xf9, 0x8d, 0x46, 0x9d, 0xe8, 0x5c, 0x14, 0x4d, 0x40, 0xd6, 0xf1, 0x6b, 0x65, - 0xe2, 0x72, 0x46, 0xa3, 0xba, 0xfc, 0x52, 0xff, 0xcd, 0xc8, 0x00, 0x4a, 0x03, 0x32, 0x50, 0xb7, - 0xe0, 0x7f, 0x1c, 0xc7, 0xb0, 0x4c, 0x19, 0x9a, 0x0b, 0x1d, 0xad, 0xac, 0x99, 0x92, 0xfb, 0xa9, - 0x1d, 0xf1, 0x89, 0x4a, 0x30, 0xda, 0xca, 0x84, 0x00, 0x42, 0x44, 0xe1, 0x52, 0x1c, 0x22, 0x92, - 0x38, 0xc5, 0xf5, 0xe6, 0xef, 0x26, 0xda, 0x88, 0x17, 0x39, 0x43, 0x1f, 0x43, 0x96, 0x6c, 0xfb, - 0x16, 0x6b, 0xe4, 0x32, 0xd3, 0xca, 0xec, 0xc8, 0xea, 0xdd, 0x40, 0xe6, 0xaf, 0x27, 0x53, 0xb7, - 0xab, 0x16, 0xdb, 0xf2, 0xcb, 0xc5, 0x0a, 0xad, 0x69, 0xf1, 0x54, 0x59, 0x5e, 0xa8, 0x6c, 0x61, - 0xcb, 0xd1, 0x9a, 0x27, 0x66, 0x10, 0x08, 0xaf, 0xb8, 0x4e, 0x5c, 0x0b, 0xdb, 0xd6, 0xa7, 0xb8, - 0x6c, 0x93, 0x35, 0x87, 0xe9, 0x12, 0x17, 0x6d, 0xc2, 0x90, 0xe5, 0xec, 0x10, 0x87, 0x51, 0xb7, - 0x91, 0x1b, 0xe8, 0xb1, 0x91, 0x16, 0x34, 0xba, 0x0b, 0x23, 0x22, 0xb4, 0x32, 0x43, 0x06, 0x79, - 0x6c, 0xa6, 0x3a, 0x86, 0x37, 0x96, 0x1e, 0xc3, 0x3b, 0xad, 0x23, 0x74, 0x0d, 0x26, 0x6a, 0xd4, - 0x63, 0x86, 0x4b, 0x2a, 0xc4, 0x61, 0x46, 0xc5, 0xb6, 0x08, 0x0f, 0xb7, 0x97, 0xcb, 0x4e, 0x67, - 0x66, 0x47, 0xf5, 0xb1, 0xe0, 0x56, 0xe7, 0x97, 0x6f, 0xf0, 0xbb, 0x35, 0xd3, 0x53, 0x0d, 0x38, - 0xc7, 0xdf, 0x7b, 0xc5, 0xb6, 0x39, 0x7c, 0x58, 0x33, 0xe8, 0x0e, 0x40, 0xab, 0x3b, 0xc8, 0x47, - 0xbf, 0x54, 0x94, 0x8d, 0x25, 0x68, 0x25, 0x45, 0xd1, 0x92, 0x64, 0x2b, 0x29, 0xde, 0xc7, 0x55, - 0x22, 0x75, 0xf5, 0x88, 0xa6, 0xfa, 0xad, 0x02, 0x13, 0xed, 0x16, 0x64, 0x56, 0xbd, 0x0e, 0x59, - 0xce, 0x3f, 0x28, 0xb7, 0xcc, 0xf1, 0x84, 0x08, 0xcb, 0xad, 0x3d, 0x1b, 0x75, 0xa9, 0x85, 0xde, - 0x8a, 0x51, 0x14, 0x49, 0x75, 0xf9, 0x44, 0x8a, 0x12, 0x24, 0xca, 0x51, 0x85, 0x69, 0x6e, 0xe6, - 0x1d, 0x52, 0xc5, 0x1c, 0x7b, 0x83, 0x32, 0x6c, 0xaf, 0x07, 0x7d, 0xa7, 0xd9, 0x43, 0x08, 0xcc, - 0x74, 0x91, 0x91, 0x1e, 0xdd, 0x86, 0x11, 0x16, 0x1c, 0x1b, 0xbc, 0x67, 0x85, 0x6d, 0x24, 0xb1, - 0x22, 0xdf, 0xf5, 0x6b, 0x52, 0x79, 0x98, 0xb5, 0x90, 0xd4, 0x07, 0xed, 0x54, 0xee, 0xed, 0x3a, - 0xc4, 0x8d, 0x51, 0x41, 0x4b, 0x70, 0x0a, 0x9b, 0xa6, 0x4b, 0x3c, 0x61, 0x60, 0x68, 0x35, 0xf7, - 0xfb, 0x0f, 0x0b, 0xe3, 0xd2, 0xef, 0x15, 0x71, 0xb3, 0xce, 0x5c, 0xcb, 0xa9, 0xea, 0xa1, 0xa0, - 0xfa, 0x73, 0xa6, 0x9d, 0x7f, 0x0c, 0x58, 0xf2, 0x7f, 0x06, 0x64, 0xf4, 0x1a, 0x64, 0xa5, 0xb7, - 0xfd, 0x29, 0xbc, 0x95, 0x89, 0x2b, 0x55, 0xd0, 0xdb, 0x30, 0xca, 0x7f, 0x19, 0xbe, 0x63, 0xd3, - 0xca, 0x27, 0x5e, 0x2e, 0xc3, 0x33, 0x21, 0x31, 0xfd, 0x39, 0xc0, 0x7b, 0x5c, 0xae, 0xd9, 0x13, - 0x5a, 0x47, 0x5e, 0xa4, 0x27, 0x0c, 0x3c, 0xa7, 0x9e, 0xd0, 0x80, 0xb1, 0x5d, 0x8b, 0x6d, 0x99, - 0x2e, 0xde, 0x0d, 0xae, 0x0c, 0x69, 0x6e, 0xb0, 0xc7, 0xe6, 0x50, 0xd4, 0xc8, 0x9b, 0xdc, 0x86, - 0x5a, 0x83, 0x17, 0xe3, 0xcf, 0xb7, 0x62, 0xdb, 0x09, 0xa9, 0xd1, 0xab, 0xaa, 0xfd, 0x5e, 0x81, - 0x97, 0xba, 0xdb, 0x93, 0x19, 0xb3, 0x02, 0x23, 0x34, 0x38, 0x6e, 0x65, 0x7c, 0xf0, 0x7e, 0x85, - 0xc4, 0x01, 0xd7, 0x54, 0xd7, 0x87, 0x69, 0x0b, 0xaa, 0x77, 0x65, 0x6c, 0xc2, 0x64, 0xab, 0x5b, - 0xc4, 0x36, 0x80, 0x5e, 0x8e, 0xc8, 0xef, 0x14, 0xc8, 0x1d, 0x37, 0xd3, 0x93, 0x41, 0xd9, 0x3e, - 0x0b, 0xfa, 0x9f, 0x75, 0x16, 0xa8, 0x7b, 0xed, 0xe9, 0xf2, 0x7e, 0x98, 0x52, 0xf6, 0x9a, 0xb3, - 0x49, 0xc3, 0xb0, 0x94, 0x00, 0x89, 0x77, 0x33, 0x18, 0x35, 0xc2, 0xac, 0x4b, 0xd5, 0xb5, 0xa4, - 0xd1, 0xb3, 0x42, 0x7d, 0x83, 0x86, 0xf8, 0xea, 0x4f, 0x99, 0xf6, 0xcc, 0x69, 0x37, 0x2d, 0x43, - 0xd5, 0x7b, 0xdb, 0xe8, 0x33, 0x05, 0x26, 0xc9, 0x5e, 0x9d, 0x54, 0x18, 0x31, 0xf9, 0x46, 0x47, - 0x8c, 0x6d, 0x1f, 0x3b, 0xcc, 0x97, 0xb1, 0xec, 0x65, 0x91, 0x9e, 0x0b, 0x0d, 0x05, 0x3b, 0x1f, - 0x29, 0x49, 0x33, 0xc8, 0x83, 0xb3, 0xb5, 0xd0, 0x71, 0xe3, 0x39, 0xad, 0x28, 0x67, 0x9a, 0x16, - 0x44, 0x73, 0x40, 0x77, 0xda, 0xc6, 0xce, 0x40, 0xfa, 0x20, 0x46, 0x87, 0xcf, 0xd2, 0x43, 0x80, - 0x41, 0xfe, 0x76, 0xe8, 0x00, 0xb2, 0x72, 0xab, 0xe8, 0x3c, 0x94, 0x63, 0x15, 0x96, 0xbf, 0x7c, - 0xa2, 0x9c, 0x78, 0x77, 0x55, 0xfd, 0xfc, 0x8f, 0x7f, 0xbe, 0xee, 0xbf, 0x88, 0xf2, 0x5a, 0xc7, - 0x7f, 0x06, 0xd0, 0x97, 0x0a, 0x0c, 0xf2, 0x0c, 0x47, 0x2f, 0x9f, 0xb4, 0x13, 0x08, 0xeb, 0x29, - 0x57, 0x07, 0x75, 0x91, 0x1b, 0xbf, 0x82, 0xe6, 0xb4, 0x4e, 0xff, 0x48, 0x68, 0xfb, 0x41, 0xd0, - 0x0f, 0xb4, 0x7d, 0x51, 0xee, 0x07, 0xe8, 0x0b, 0x05, 0x86, 0x9a, 0xbb, 0x0b, 0x9a, 0xeb, 0x68, - 0xa8, 0x7d, 0x83, 0xca, 0xcf, 0xa7, 0x11, 0x95, 0xbc, 0x66, 0x38, 0xaf, 0x0b, 0xe8, 0x7c, 0x47, - 0x5e, 0xe8, 0x47, 0x05, 0xc6, 0x93, 0x96, 0x0f, 0xb4, 0xdc, 0xd1, 0x4e, 0x97, 0x7d, 0x26, 0x7f, - 0xfd, 0x29, 0xb5, 0x24, 0xd1, 0x25, 0x4e, 0xf4, 0x2a, 0x9a, 0x4f, 0x22, 0xda, 0xcc, 0x4b, 0x2d, - 0x9a, 0x8e, 0xe8, 0x97, 0x28, 0xf3, 0xc8, 0x10, 0x49, 0xc3, 0xfc, 0xf8, 0x8c, 0x4b, 0xc3, 0x3c, - 0x61, 0x52, 0xa9, 0xb7, 0x38, 0xf3, 0x1b, 0x68, 0xb9, 0x3b, 0xf3, 0xe8, 0x34, 0xd3, 0xf6, 0xe5, - 0x92, 0x73, 0x80, 0x1e, 0x2a, 0x30, 0xd9, 0x61, 0x16, 0xa2, 0x9b, 0x27, 0x13, 0x4a, 0x9c, 0xd6, - 0xf9, 0x57, 0x9f, 0x5e, 0x51, 0x3a, 0x73, 0x83, 0x3b, 0xf3, 0x0a, 0x2a, 0x76, 0x77, 0x06, 0xdb, - 0xb6, 0x11, 0x75, 0x08, 0x7d, 0xa3, 0xc0, 0x70, 0x64, 0x74, 0xa0, 0x2b, 0xdd, 0xeb, 0x26, 0x5e, - 0xe2, 0x57, 0xd3, 0x09, 0xa7, 0xc9, 0x14, 0x51, 0xe7, 0xc7, 0x6a, 0xed, 0xd7, 0x68, 0x94, 0xe3, - 0x73, 0x23, 0x4d, 0x94, 0x13, 0x87, 0x5c, 0x9a, 0x28, 0x27, 0x8f, 0x28, 0xf5, 0x3a, 0x77, 0x41, - 0x43, 0x0b, 0xdd, 0xa3, 0xdc, 0x5c, 0xd7, 0x6c, 0xc3, 0x72, 0x36, 0xe9, 0x6a, 0xe9, 0xd1, 0x61, - 0x41, 0x79, 0x7c, 0x58, 0x50, 0xfe, 0x3e, 0x2c, 0x28, 0x5f, 0x1d, 0x15, 0xfa, 0x1e, 0x1f, 0x15, - 0xfa, 0xfe, 0x3c, 0x2a, 0xf4, 0x7d, 0x70, 0x33, 0x7d, 0xef, 0xdf, 0x93, 0x66, 0xf8, 0x08, 0x28, - 0x67, 0xf9, 0xf9, 0xb5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x87, 0xf2, 0x87, 0x5d, 0x1b, 0x12, - 0x00, 0x00, + // 1284 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xc6, 0x89, 0x4b, 0x5f, 0x92, 0xb6, 0x4c, 0xd3, 0xd4, 0x75, 0x8b, 0x93, 0x2c, 0xd0, + 0x26, 0x69, 0xe3, 0x25, 0x6e, 0x68, 0x2b, 0xa8, 0x50, 0x13, 0x44, 0x69, 0x90, 0xa0, 0xf5, 0x26, + 0x14, 0x09, 0x09, 0x96, 0xb1, 0x77, 0xe2, 0xac, 0x58, 0xef, 0x38, 0xbb, 0xb3, 0x49, 0x4c, 0x14, + 0x09, 0x21, 0x71, 0xe0, 0x86, 0xc4, 0x95, 0x0b, 0x7c, 0x04, 0x84, 0x84, 0x38, 0x70, 0x40, 0x42, + 0xb4, 0xc7, 0x0a, 0x2e, 0x88, 0x43, 0x85, 0x12, 0xce, 0x7c, 0x06, 0xb4, 0x33, 0xb3, 0xf6, 0xae, + 0xb3, 0x76, 0xb6, 0x95, 0x7b, 0x89, 0xbc, 0x33, 0xef, 0xfd, 0xde, 0xef, 0xbd, 0x79, 0xff, 0x02, + 0x05, 0xb3, 0x69, 0xee, 0x34, 0x5c, 0xca, 0x68, 0x95, 0xda, 0xda, 0x16, 0xf6, 0x6d, 0xa6, 0x6d, + 0xfa, 0xc4, 0x6d, 0x16, 0xf9, 0x21, 0x42, 0xd1, 0xfb, 0x22, 0xbf, 0xcf, 0x9f, 0xab, 0x52, 0xaf, + 0x4e, 0x3d, 0x83, 0x1f, 0x6b, 0xe2, 0x43, 0x88, 0xe7, 0xe7, 0xc4, 0x97, 0x56, 0xc1, 0x1e, 0x11, + 0x38, 0xda, 0xd6, 0x42, 0x85, 0x30, 0xbc, 0xa0, 0x35, 0x70, 0xcd, 0x72, 0x30, 0xb3, 0xa8, 0x23, + 0x65, 0xc7, 0x6b, 0xb4, 0x46, 0x05, 0x46, 0xf0, 0x4b, 0x9e, 0x5e, 0xa8, 0x51, 0x5a, 0xb3, 0x89, + 0x86, 0x1b, 0x96, 0x86, 0x1d, 0x87, 0x32, 0xae, 0x12, 0xe2, 0xcf, 0xc6, 0xe8, 0x7a, 0x7e, 0x05, + 0x57, 0xab, 0xd4, 0x77, 0x98, 0x17, 0xf9, 0x2d, 0x45, 0x27, 0x13, 0x3c, 0x6b, 0x60, 0x17, 0xd7, + 0x43, 0xac, 0x24, 0xd7, 0xbd, 0x0d, 0xec, 0x92, 0x1e, 0xf7, 0xfc, 0xaf, 0xb8, 0x57, 0xc7, 0x01, + 0x95, 0x03, 0x0f, 0xef, 0x71, 0x50, 0x9d, 0x6c, 0xfa, 0xc4, 0x63, 0xea, 0x03, 0x05, 0x4e, 0xc7, + 0x8e, 0xbd, 0x06, 0x75, 0x3c, 0x82, 0x3e, 0x82, 0x09, 0x93, 0xac, 0x07, 0xea, 0xc6, 0xa6, 0x4f, + 0x99, 0xe5, 0xd4, 0x0c, 0xc1, 0x26, 0xa7, 0x4c, 0x29, 0x33, 0x23, 0xa5, 0xe9, 0xe2, 0xe1, 0x48, + 0x17, 0xcb, 0x42, 0x52, 0x40, 0x2d, 0x0f, 0x3d, 0x7c, 0x3c, 0x39, 0xa0, 0x8f, 0x4b, 0x98, 0xd8, + 0x1d, 0x2a, 0xc3, 0x49, 0xda, 0x20, 0x2e, 0x66, 0xd4, 0x0d, 0x71, 0x07, 0x39, 0xae, 0x9a, 0x84, + 0x7b, 0x57, 0x8a, 0xc6, 0x80, 0x4f, 0xd0, 0xd8, 0xa9, 0xfa, 0x31, 0x3c, 0xcf, 0x1d, 0xb9, 0x1f, + 0xa8, 0x48, 0xf7, 0xd0, 0x02, 0x0c, 0xb1, 0x66, 0x83, 0x70, 0xd2, 0x27, 0x4a, 0x2f, 0x24, 0x81, + 0x73, 0xf9, 0xb5, 0x66, 0x83, 0xe8, 0x5c, 0x14, 0x4d, 0x40, 0xd6, 0xf1, 0xeb, 0x15, 0xe2, 0x72, + 0x46, 0x63, 0xba, 0xfc, 0x52, 0xff, 0xcb, 0xc8, 0x00, 0x4a, 0x03, 0x32, 0x50, 0x37, 0xe1, 0x39, + 0x8e, 0x63, 0x58, 0xa6, 0x0c, 0xcd, 0xf9, 0xae, 0x56, 0x56, 0x4c, 0xc9, 0xfd, 0xd8, 0x96, 0xf8, + 0x44, 0x65, 0x18, 0x6b, 0x67, 0x42, 0x00, 0x21, 0xa2, 0x70, 0x31, 0x0e, 0x11, 0x49, 0x9c, 0xe2, + 0x6a, 0xeb, 0x77, 0x0b, 0x6d, 0xd4, 0x8b, 0x9c, 0xa1, 0x4f, 0x20, 0x4b, 0x36, 0x7d, 0x8b, 0x35, + 0x73, 0x99, 0x29, 0x65, 0x66, 0x74, 0xf9, 0x4e, 0x20, 0xf3, 0xf7, 0xe3, 0xc9, 0x5b, 0x35, 0x8b, + 0x6d, 0xf8, 0x95, 0x62, 0x95, 0xd6, 0xb5, 0x78, 0xaa, 0x2c, 0xce, 0x57, 0x37, 0xb0, 0xe5, 0x68, + 0xad, 0x13, 0x33, 0x08, 0x84, 0x57, 0x5c, 0x25, 0xae, 0x85, 0x6d, 0xeb, 0x33, 0x5c, 0xb1, 0xc9, + 0x8a, 0xc3, 0x74, 0x89, 0x8b, 0xd6, 0xe1, 0xb8, 0xe5, 0x6c, 0x11, 0x87, 0x51, 0xb7, 0x99, 0x1b, + 0xea, 0xb3, 0x91, 0x36, 0x34, 0xba, 0x03, 0xa3, 0x22, 0xb4, 0x32, 0x43, 0x86, 0x79, 0x6c, 0x26, + 0xbb, 0x86, 0x37, 0x96, 0x1e, 0x23, 0x5b, 0xed, 0x23, 0x74, 0x15, 0x26, 0xea, 0xd4, 0x63, 0x86, + 0x4b, 0xaa, 0xc4, 0x61, 0x46, 0xd5, 0xb6, 0x08, 0x0f, 0xb7, 0x97, 0xcb, 0x4e, 0x65, 0x66, 0xc6, + 0xf4, 0xd3, 0xc1, 0xad, 0xce, 0x2f, 0xdf, 0xe4, 0x77, 0x2b, 0xa6, 0xa7, 0x1a, 0x70, 0x86, 0xbf, + 0xf7, 0x92, 0x6d, 0x73, 0xf8, 0xb0, 0x66, 0xd0, 0x6d, 0x80, 0x76, 0x77, 0x90, 0x8f, 0x7e, 0xb1, + 0x28, 0x1b, 0x4b, 0xd0, 0x4a, 0x8a, 0xa2, 0x25, 0xc9, 0x56, 0x52, 0xbc, 0x87, 0x6b, 0x44, 0xea, + 0xea, 0x11, 0x4d, 0xf5, 0x3b, 0x05, 0x26, 0x3a, 0x2d, 0xc8, 0xac, 0x7a, 0x03, 0xb2, 0x9c, 0x7f, + 0x50, 0x6e, 0x99, 0xc3, 0x09, 0x11, 0x96, 0x5b, 0x67, 0x36, 0xea, 0x52, 0x0b, 0xbd, 0x1d, 0xa3, + 0x28, 0x92, 0xea, 0xd2, 0x91, 0x14, 0x25, 0x48, 0x94, 0xa3, 0x0a, 0x53, 0xdc, 0xcc, 0xbb, 0xa4, + 0x86, 0x39, 0xf6, 0x1a, 0x65, 0xd8, 0x5e, 0x0d, 0xfa, 0x4e, 0xab, 0x87, 0x10, 0x98, 0xee, 0x21, + 0x23, 0x3d, 0xba, 0x05, 0xa3, 0x2c, 0x38, 0x36, 0x78, 0xcf, 0x0a, 0xdb, 0x48, 0x62, 0x45, 0xbe, + 0xe7, 0xd7, 0xa5, 0xf2, 0x08, 0x6b, 0x23, 0xa9, 0xf7, 0x3b, 0xa9, 0xdc, 0xdd, 0x76, 0x88, 0x1b, + 0xa3, 0x82, 0x4a, 0x70, 0x0c, 0x9b, 0xa6, 0x4b, 0x3c, 0x61, 0xe0, 0xf8, 0x72, 0xee, 0x8f, 0x1f, + 0xe7, 0xc7, 0xa5, 0xdf, 0x4b, 0xe2, 0x66, 0x95, 0xb9, 0x96, 0x53, 0xd3, 0x43, 0x41, 0xf5, 0x97, + 0x4c, 0x27, 0xff, 0x18, 0xb0, 0xe4, 0xff, 0x14, 0xc8, 0xe8, 0x75, 0xc8, 0x4a, 0x6f, 0x07, 0x53, + 0x78, 0x2b, 0x13, 0x57, 0xaa, 0xa0, 0x77, 0x60, 0x8c, 0xff, 0x32, 0x7c, 0xc7, 0xa6, 0xd5, 0x4f, + 0xbd, 0x5c, 0x86, 0x67, 0x42, 0x62, 0xfa, 0x73, 0x80, 0xf7, 0xb9, 0x5c, 0xab, 0x27, 0xb4, 0x8f, + 0xbc, 0x48, 0x4f, 0x18, 0x7a, 0x46, 0x3d, 0xa1, 0x09, 0xa7, 0xb7, 0x2d, 0xb6, 0x61, 0xba, 0x78, + 0x3b, 0xb8, 0x32, 0xa4, 0xb9, 0xe1, 0x3e, 0x9b, 0x43, 0x51, 0x23, 0x6f, 0x71, 0x1b, 0x6a, 0x1d, + 0x5e, 0x8c, 0x3f, 0xdf, 0x92, 0x6d, 0x27, 0xa4, 0x46, 0xbf, 0xaa, 0xf6, 0x07, 0x05, 0x5e, 0xea, + 0x6d, 0x4f, 0x66, 0xcc, 0x12, 0x8c, 0xd2, 0xe0, 0xb8, 0x9d, 0xf1, 0xc1, 0xfb, 0x15, 0x12, 0x07, + 0x5c, 0x4b, 0x5d, 0x1f, 0xa1, 0x6d, 0xa8, 0xfe, 0x95, 0xb1, 0x09, 0x67, 0xdb, 0xdd, 0x22, 0xb6, + 0x01, 0xf4, 0x73, 0x44, 0x7e, 0xaf, 0x40, 0xee, 0xb0, 0x99, 0xbe, 0x0c, 0xca, 0xce, 0x59, 0x30, + 0xf8, 0xb4, 0xb3, 0x40, 0xdd, 0xe9, 0x4c, 0x97, 0x0f, 0xc2, 0x94, 0xb2, 0x57, 0x9c, 0x75, 0x1a, + 0x86, 0xa5, 0x0c, 0x48, 0xbc, 0x9b, 0xc1, 0xa8, 0x11, 0x66, 0x5d, 0xaa, 0xae, 0x25, 0x8d, 0x9e, + 0x12, 0xea, 0x6b, 0x34, 0xc4, 0x57, 0x7f, 0xce, 0x74, 0x66, 0x4e, 0xa7, 0x69, 0x19, 0xaa, 0xfe, + 0xdb, 0x46, 0x9f, 0x2b, 0x70, 0x96, 0xec, 0x34, 0x48, 0x95, 0x11, 0x93, 0x6f, 0x74, 0xc4, 0xd8, + 0xf4, 0xb1, 0xc3, 0x7c, 0x19, 0xcb, 0x7e, 0x16, 0xe9, 0x99, 0xd0, 0x50, 0xb0, 0xf3, 0x91, 0xb2, + 0x34, 0x83, 0x3c, 0x38, 0x55, 0x0f, 0x1d, 0x37, 0x9e, 0xd1, 0x8a, 0x72, 0xb2, 0x65, 0x41, 0x34, + 0x07, 0x74, 0xbb, 0x63, 0xec, 0x0c, 0xa5, 0x0f, 0x62, 0x74, 0xf8, 0x94, 0x1e, 0x00, 0x0c, 0xf3, + 0xb7, 0x43, 0x7b, 0x90, 0x95, 0x5b, 0x45, 0xf7, 0xa1, 0x1c, 0xab, 0xb0, 0xfc, 0xa5, 0x23, 0xe5, + 0xc4, 0xbb, 0xab, 0xea, 0x17, 0x7f, 0xfe, 0xfb, 0xcd, 0xe0, 0x05, 0x94, 0xd7, 0xba, 0xfe, 0x33, + 0x80, 0xbe, 0x52, 0x60, 0x98, 0x67, 0x38, 0x7a, 0xf9, 0xa8, 0x9d, 0x40, 0x58, 0x4f, 0xb9, 0x3a, + 0xa8, 0x0b, 0xdc, 0xf8, 0x65, 0x34, 0xab, 0x75, 0xfb, 0x47, 0x42, 0xdb, 0x0d, 0x82, 0xbe, 0xa7, + 0xed, 0x8a, 0x72, 0xdf, 0x43, 0x5f, 0x2a, 0x70, 0xbc, 0xb5, 0xbb, 0xa0, 0xd9, 0xae, 0x86, 0x3a, + 0x37, 0xa8, 0xfc, 0x5c, 0x1a, 0x51, 0xc9, 0x6b, 0x9a, 0xf3, 0x3a, 0x8f, 0xce, 0x75, 0xe5, 0x85, + 0x7e, 0x52, 0x60, 0x3c, 0x69, 0xf9, 0x40, 0x8b, 0x5d, 0xed, 0xf4, 0xd8, 0x67, 0xf2, 0xaf, 0x3e, + 0xa1, 0x96, 0x24, 0x5a, 0xe2, 0x44, 0xaf, 0xa0, 0xb9, 0x24, 0xa2, 0xad, 0xbc, 0xd4, 0xa2, 0xe9, + 0x88, 0x7e, 0x8d, 0x32, 0x8f, 0x0c, 0x91, 0x34, 0xcc, 0x0f, 0xcf, 0xb8, 0x34, 0xcc, 0x13, 0x26, + 0x95, 0x7a, 0x93, 0x33, 0xbf, 0x86, 0x16, 0x7b, 0x33, 0x8f, 0x4e, 0x33, 0x6d, 0x57, 0x2e, 0x39, + 0x7b, 0xe8, 0x37, 0x05, 0xce, 0x76, 0x99, 0x85, 0xe8, 0xfa, 0xd1, 0x84, 0x12, 0xa7, 0x75, 0xfe, + 0xc6, 0x93, 0x2b, 0x4a, 0x67, 0xae, 0x71, 0x67, 0x5e, 0x41, 0xc5, 0xde, 0xce, 0x60, 0xdb, 0x36, + 0xa2, 0x0e, 0xa1, 0x6f, 0x15, 0x18, 0x89, 0x8c, 0x0e, 0x74, 0xb9, 0x77, 0xdd, 0xc4, 0x4b, 0xfc, + 0x4a, 0x3a, 0xe1, 0x34, 0x99, 0x22, 0xea, 0xfc, 0x50, 0xad, 0xfd, 0x1e, 0x8d, 0x72, 0x7c, 0x6e, + 0xa4, 0x89, 0x72, 0xe2, 0x90, 0x4b, 0x13, 0xe5, 0xe4, 0x11, 0xa5, 0xde, 0xe0, 0x2e, 0x94, 0x5e, + 0x53, 0xe6, 0xd4, 0xf9, 0xde, 0x81, 0x6e, 0x6d, 0x6c, 0xb6, 0x61, 0x39, 0xeb, 0x74, 0xb9, 0xfc, + 0x70, 0xbf, 0xa0, 0x3c, 0xda, 0x2f, 0x28, 0xff, 0xec, 0x17, 0x94, 0xaf, 0x0f, 0x0a, 0x03, 0x8f, + 0x0e, 0x0a, 0x03, 0x7f, 0x1d, 0x14, 0x06, 0x3e, 0xbc, 0x9e, 0xbe, 0xfd, 0xef, 0x48, 0x33, 0x7c, + 0x0a, 0x54, 0xb2, 0xfc, 0xfc, 0xea, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x04, 0x45, 0xd1, 0x47, + 0x1e, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/protocol/x/vault/types/query.pb.gw.go b/protocol/x/vault/types/query.pb.gw.go index dc98d0799f..bfafbe93d1 100644 --- a/protocol/x/vault/types/query.pb.gw.go +++ b/protocol/x/vault/types/query.pb.gw.go @@ -359,18 +359,15 @@ func local_request_Query_VaultParams_0(ctx context.Context, marshaler runtime.Ma } -var ( - filter_Query_MegavaultWithdrawalInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - func request_Query_MegavaultWithdrawalInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryMegavaultWithdrawalInfoRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_MegavaultWithdrawalInfo_0); err != nil { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -383,10 +380,11 @@ func local_request_Query_MegavaultWithdrawalInfo_0(ctx context.Context, marshale var protoReq QueryMegavaultWithdrawalInfoRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_MegavaultWithdrawalInfo_0); err != nil { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -562,7 +560,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_MegavaultWithdrawalInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Query_MegavaultWithdrawalInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -766,7 +764,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_MegavaultWithdrawalInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Query_MegavaultWithdrawalInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) From 50d7a45645e1348a705a2fbb1594536d79b40d64 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Tue, 5 Nov 2024 17:21:51 -0500 Subject: [PATCH 106/120] Add gRPC gateway routing for affiliate queries (#2554) --- .../dydxprotocol/affiliates/query.lcd.ts | 46 ++ .../src/codegen/dydxprotocol/bundle.ts | 238 +++++----- .../v4-protos/src/codegen/dydxprotocol/lcd.ts | 3 + proto/dydxprotocol/affiliates/query.proto | 21 +- protocol/x/affiliates/module.go | 7 +- protocol/x/affiliates/types/query.pb.go | 82 ++-- protocol/x/affiliates/types/query.pb.gw.go | 420 ++++++++++++++++++ 7 files changed, 656 insertions(+), 161 deletions(-) create mode 100644 indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/query.lcd.ts create mode 100644 protocol/x/affiliates/types/query.pb.gw.go diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/query.lcd.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/query.lcd.ts new file mode 100644 index 0000000000..4abc5b7a4a --- /dev/null +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/affiliates/query.lcd.ts @@ -0,0 +1,46 @@ +import { LCDClient } from "@osmonauts/lcd"; +import { AffiliateInfoRequest, AffiliateInfoResponseSDKType, ReferredByRequest, ReferredByResponseSDKType, AllAffiliateTiersRequest, AllAffiliateTiersResponseSDKType, AffiliateWhitelistRequest, AffiliateWhitelistResponseSDKType } from "./query"; +export class LCDQueryClient { + req: LCDClient; + + constructor({ + requestClient + }: { + requestClient: LCDClient; + }) { + this.req = requestClient; + this.affiliateInfo = this.affiliateInfo.bind(this); + this.referredBy = this.referredBy.bind(this); + this.allAffiliateTiers = this.allAffiliateTiers.bind(this); + this.affiliateWhitelist = this.affiliateWhitelist.bind(this); + } + /* Query AffiliateInfo returns the affiliate info for a given address. */ + + + async affiliateInfo(params: AffiliateInfoRequest): Promise { + const endpoint = `dydxprotocol/affiliates/affiliate_info/${params.address}`; + return await this.req.get(endpoint); + } + /* Query ReferredBy returns the affiliate that referred a given address. */ + + + async referredBy(params: ReferredByRequest): Promise { + const endpoint = `dydxprotocol/affiliates/referred_by/${params.address}`; + return await this.req.get(endpoint); + } + /* Query AllAffiliateTiers returns all affiliate tiers. */ + + + async allAffiliateTiers(_params: AllAffiliateTiersRequest = {}): Promise { + const endpoint = `dydxprotocol/affiliates/all_affiliate_tiers`; + return await this.req.get(endpoint); + } + /* Query AffiliateWhitelist returns the affiliate whitelist. */ + + + async affiliateWhitelist(_params: AffiliateWhitelistRequest = {}): Promise { + const endpoint = `dydxprotocol/affiliates/affiliate_whitelist`; + return await this.req.get(endpoint); + } + +} \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts index 3550eca53c..42aaa1e67a 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts @@ -123,65 +123,66 @@ 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 "./assets/query.lcd"; -import * as _138 from "./blocktime/query.lcd"; -import * as _139 from "./bridge/query.lcd"; -import * as _140 from "./clob/query.lcd"; -import * as _141 from "./delaymsg/query.lcd"; -import * as _142 from "./epochs/query.lcd"; -import * as _143 from "./feetiers/query.lcd"; -import * as _144 from "./listing/query.lcd"; -import * as _145 from "./perpetuals/query.lcd"; -import * as _146 from "./prices/query.lcd"; -import * as _147 from "./ratelimit/query.lcd"; -import * as _148 from "./revshare/query.lcd"; -import * as _149 from "./rewards/query.lcd"; -import * as _150 from "./stats/query.lcd"; -import * as _151 from "./subaccounts/query.lcd"; -import * as _152 from "./vault/query.lcd"; -import * as _153 from "./vest/query.lcd"; -import * as _154 from "./accountplus/query.rpc.Query"; -import * as _155 from "./affiliates/query.rpc.Query"; -import * as _156 from "./assets/query.rpc.Query"; -import * as _157 from "./blocktime/query.rpc.Query"; -import * as _158 from "./bridge/query.rpc.Query"; -import * as _159 from "./clob/query.rpc.Query"; -import * as _160 from "./delaymsg/query.rpc.Query"; -import * as _161 from "./epochs/query.rpc.Query"; -import * as _162 from "./feetiers/query.rpc.Query"; -import * as _163 from "./govplus/query.rpc.Query"; -import * as _164 from "./listing/query.rpc.Query"; -import * as _165 from "./perpetuals/query.rpc.Query"; -import * as _166 from "./prices/query.rpc.Query"; -import * as _167 from "./ratelimit/query.rpc.Query"; -import * as _168 from "./revshare/query.rpc.Query"; -import * as _169 from "./rewards/query.rpc.Query"; -import * as _170 from "./sending/query.rpc.Query"; -import * as _171 from "./stats/query.rpc.Query"; -import * as _172 from "./subaccounts/query.rpc.Query"; -import * as _173 from "./vault/query.rpc.Query"; -import * as _174 from "./vest/query.rpc.Query"; -import * as _175 from "./accountplus/tx.rpc.msg"; -import * as _176 from "./affiliates/tx.rpc.msg"; -import * as _177 from "./blocktime/tx.rpc.msg"; -import * as _178 from "./bridge/tx.rpc.msg"; -import * as _179 from "./clob/tx.rpc.msg"; -import * as _180 from "./delaymsg/tx.rpc.msg"; -import * as _181 from "./feetiers/tx.rpc.msg"; -import * as _182 from "./govplus/tx.rpc.msg"; -import * as _183 from "./listing/tx.rpc.msg"; -import * as _184 from "./perpetuals/tx.rpc.msg"; -import * as _185 from "./prices/tx.rpc.msg"; -import * as _186 from "./ratelimit/tx.rpc.msg"; -import * as _187 from "./revshare/tx.rpc.msg"; -import * as _188 from "./rewards/tx.rpc.msg"; -import * as _189 from "./sending/tx.rpc.msg"; -import * as _190 from "./stats/tx.rpc.msg"; -import * as _191 from "./vault/tx.rpc.msg"; -import * as _192 from "./vest/tx.rpc.msg"; -import * as _193 from "./lcd"; -import * as _194 from "./rpc.query"; -import * as _195 from "./rpc.tx"; +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"; export namespace dydxprotocol { export const accountplus = { ..._5, ..._6, @@ -190,31 +191,32 @@ export namespace dydxprotocol { ..._9, ..._10, ..._136, - ..._154, - ..._175 + ..._155, + ..._176 }; export const affiliates = { ..._11, ..._12, ..._13, ..._14, - ..._155, - ..._176 + ..._137, + ..._156, + ..._177 }; export const assets = { ..._15, ..._16, ..._17, ..._18, - ..._137, - ..._156 + ..._138, + ..._157 }; export const blocktime = { ..._19, ..._20, ..._21, ..._22, ..._23, - ..._138, - ..._157, - ..._177 + ..._139, + ..._158, + ..._178 }; export const bridge = { ..._24, ..._25, @@ -222,9 +224,9 @@ export namespace dydxprotocol { ..._27, ..._28, ..._29, - ..._139, - ..._158, - ..._178 + ..._140, + ..._159, + ..._179 }; export const clob = { ..._30, ..._31, @@ -242,9 +244,9 @@ export namespace dydxprotocol { ..._43, ..._44, ..._45, - ..._140, - ..._159, - ..._179 + ..._141, + ..._160, + ..._180 }; export namespace daemons { export const bridge = { ..._46 @@ -259,29 +261,29 @@ export namespace dydxprotocol { ..._51, ..._52, ..._53, - ..._141, - ..._160, - ..._180 + ..._142, + ..._161, + ..._181 }; export const epochs = { ..._54, ..._55, ..._56, - ..._142, - ..._161 + ..._143, + ..._162 }; export const feetiers = { ..._57, ..._58, ..._59, ..._60, - ..._143, - ..._162, - ..._181 + ..._144, + ..._163, + ..._182 }; export const govplus = { ..._61, ..._62, ..._63, - ..._163, - ..._182 + ..._164, + ..._183 }; export namespace indexer { export const events = { ..._64 @@ -308,27 +310,27 @@ export namespace dydxprotocol { ..._75, ..._76, ..._77, - ..._144, - ..._164, - ..._183 + ..._145, + ..._165, + ..._184 }; export const perpetuals = { ..._78, ..._79, ..._80, ..._81, ..._82, - ..._145, - ..._165, - ..._184 + ..._146, + ..._166, + ..._185 }; export const prices = { ..._83, ..._84, ..._85, ..._86, ..._87, - ..._146, - ..._166, - ..._185 + ..._147, + ..._167, + ..._186 }; export const ratelimit = { ..._88, ..._89, @@ -336,43 +338,43 @@ export namespace dydxprotocol { ..._91, ..._92, ..._93, - ..._147, - ..._167, - ..._186 + ..._148, + ..._168, + ..._187 }; export const revshare = { ..._94, ..._95, ..._96, ..._97, ..._98, - ..._148, - ..._168, - ..._187 + ..._149, + ..._169, + ..._188 }; export const rewards = { ..._99, ..._100, ..._101, ..._102, ..._103, - ..._149, - ..._169, - ..._188 + ..._150, + ..._170, + ..._189 }; export const sending = { ..._104, ..._105, ..._106, ..._107, - ..._170, - ..._189 + ..._171, + ..._190 }; export const stats = { ..._108, ..._109, ..._110, ..._111, ..._112, - ..._150, - ..._171, - ..._190 + ..._151, + ..._172, + ..._191 }; export const subaccounts = { ..._113, ..._114, @@ -380,8 +382,8 @@ export namespace dydxprotocol { ..._116, ..._117, ..._118, - ..._151, - ..._172 + ..._152, + ..._173 }; export const vault = { ..._119, ..._120, @@ -389,20 +391,20 @@ export namespace dydxprotocol { ..._122, ..._123, ..._124, - ..._152, - ..._173, - ..._191 + ..._153, + ..._174, + ..._192 }; export const vest = { ..._125, ..._126, ..._127, ..._128, - ..._153, - ..._174, - ..._192 + ..._154, + ..._175, + ..._193 }; - export const ClientFactory = { ..._193, - ..._194, - ..._195 + export const ClientFactory = { ..._194, + ..._195, + ..._196 }; } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/lcd.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/lcd.ts index dd77cee074..7a332c4c8e 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/lcd.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/lcd.ts @@ -12,6 +12,9 @@ export const createLCDClient = async ({ accountplus: new (await import("./accountplus/query.lcd")).LCDQueryClient({ requestClient }), + affiliates: new (await import("./affiliates/query.lcd")).LCDQueryClient({ + requestClient + }), assets: new (await import("./assets/query.lcd")).LCDQueryClient({ requestClient }), diff --git a/proto/dydxprotocol/affiliates/query.proto b/proto/dydxprotocol/affiliates/query.proto index 16fdb2f242..9e2c612e70 100644 --- a/proto/dydxprotocol/affiliates/query.proto +++ b/proto/dydxprotocol/affiliates/query.proto @@ -4,21 +4,34 @@ package dydxprotocol.affiliates; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "dydxprotocol/affiliates/affiliates.proto"; +import "google/api/annotations.proto"; option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types"; // Query defines the gRPC querier service. service Query { // Query AffiliateInfo returns the affiliate info for a given address. - rpc AffiliateInfo(AffiliateInfoRequest) returns (AffiliateInfoResponse); + rpc AffiliateInfo(AffiliateInfoRequest) returns (AffiliateInfoResponse) { + option (google.api.http).get = + "/dydxprotocol/affiliates/affiliate_info/{address}"; + }; // Query ReferredBy returns the affiliate that referred a given address. - rpc ReferredBy(ReferredByRequest) returns (ReferredByResponse); + rpc ReferredBy(ReferredByRequest) returns (ReferredByResponse) { + option (google.api.http).get = + "/dydxprotocol/affiliates/referred_by/{address}"; + }; // Query AllAffiliateTiers returns all affiliate tiers. rpc AllAffiliateTiers(AllAffiliateTiersRequest) - returns (AllAffiliateTiersResponse); + returns (AllAffiliateTiersResponse) { + option (google.api.http).get = + "/dydxprotocol/affiliates/all_affiliate_tiers"; + }; // Query AffiliateWhitelist returns the affiliate whitelist. rpc AffiliateWhitelist(AffiliateWhitelistRequest) - returns (AffiliateWhitelistResponse); + returns (AffiliateWhitelistResponse) { + option (google.api.http).get = + "/dydxprotocol/affiliates/affiliate_whitelist"; + }; } // AffiliateInfoRequest is the request type for the Query/AffiliateInfo RPC diff --git a/protocol/x/affiliates/module.go b/protocol/x/affiliates/module.go index db70ee60a0..d2cbb7502e 100644 --- a/protocol/x/affiliates/module.go +++ b/protocol/x/affiliates/module.go @@ -78,7 +78,12 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} // GetTxCmd returns the root Tx command for the module. The subcommands of this root command are used by end-users to // generate new transactions containing messages defined in the module. diff --git a/protocol/x/affiliates/types/query.pb.go b/protocol/x/affiliates/types/query.pb.go index dccbda4dc8..5ba1fd76db 100644 --- a/protocol/x/affiliates/types/query.pb.go +++ b/protocol/x/affiliates/types/query.pb.go @@ -11,6 +11,7 @@ import ( grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" github_com_dydxprotocol_v4_chain_protocol_dtypes "github.com/dydxprotocol/v4-chain/protocol/dtypes" + _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -424,44 +425,49 @@ func init() { } var fileDescriptor_2edc1b3ea39b05a9 = []byte{ - // 583 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0x8e, 0xfb, 0x03, 0x74, 0xda, 0x14, 0xba, 0x2a, 0xc2, 0x35, 0x92, 0x5b, 0x19, 0x21, 0x22, - 0xaa, 0x3a, 0x22, 0xe5, 0xc8, 0x81, 0x04, 0x21, 0x28, 0x17, 0xc0, 0x41, 0x45, 0x82, 0x83, 0x71, - 0xe2, 0x71, 0xb2, 0xc2, 0xf6, 0x3a, 0xde, 0x4d, 0x69, 0x2a, 0xf1, 0x0e, 0x3c, 0x0c, 0x0f, 0xd1, - 0x63, 0xc5, 0xa9, 0x70, 0xa8, 0x50, 0xf2, 0x22, 0x28, 0xf6, 0xc6, 0x49, 0x48, 0xa3, 0x26, 0x82, - 0xdb, 0x7a, 0xbe, 0x99, 0xef, 0x1b, 0xef, 0x37, 0xb3, 0x70, 0xcf, 0xed, 0xb8, 0xc7, 0x51, 0xcc, - 0x04, 0xab, 0x33, 0xbf, 0xe8, 0x78, 0x1e, 0xf5, 0xa9, 0x23, 0x90, 0x17, 0x5b, 0x6d, 0x8c, 0x3b, - 0x66, 0x82, 0x90, 0x3b, 0xa3, 0x49, 0xe6, 0x30, 0x49, 0xdb, 0xaa, 0x33, 0x1e, 0x30, 0x6e, 0x27, - 0x58, 0x31, 0xfd, 0x48, 0x6b, 0xb4, 0xcd, 0x06, 0x6b, 0xb0, 0x34, 0xde, 0x3f, 0xc9, 0x68, 0x61, - 0x9a, 0xdc, 0xf0, 0x98, 0x66, 0x1a, 0xaf, 0x60, 0xb3, 0x3c, 0x88, 0x1d, 0x84, 0x1e, 0xb3, 0xb0, - 0xd5, 0x46, 0x2e, 0x48, 0x09, 0xae, 0x3b, 0xae, 0x1b, 0x23, 0xe7, 0xaa, 0xb2, 0xa3, 0x14, 0x56, - 0x2a, 0xea, 0x8f, 0xef, 0x7b, 0x9b, 0x52, 0xba, 0x9c, 0x22, 0x55, 0x11, 0xd3, 0xb0, 0x61, 0x0d, - 0x12, 0x8d, 0xf3, 0x05, 0xb8, 0xfd, 0x17, 0x19, 0x8f, 0x58, 0xc8, 0x91, 0xdc, 0x87, 0x75, 0xca, - 0xed, 0x2f, 0x4d, 0x2a, 0xd0, 0xa7, 0x5c, 0xa0, 0x9b, 0x90, 0xde, 0xb0, 0xf2, 0x94, 0xbf, 0x1f, - 0x06, 0x09, 0x81, 0x25, 0x41, 0x31, 0x56, 0x17, 0x76, 0x94, 0x42, 0xde, 0x4a, 0xce, 0xc4, 0x80, - 0xbc, 0x87, 0x68, 0xf3, 0xa6, 0x13, 0xa3, 0x1d, 0x45, 0x81, 0xba, 0x98, 0x80, 0xab, 0x1e, 0x62, - 0xb5, 0x1f, 0x7b, 0x13, 0x05, 0xa4, 0x05, 0x37, 0x63, 0xf4, 0x30, 0x8e, 0xd1, 0xb5, 0x8f, 0x98, - 0xdf, 0x0e, 0x50, 0x5d, 0xda, 0x51, 0x0a, 0x6b, 0x95, 0x97, 0xa7, 0x17, 0xdb, 0xb9, 0x5f, 0x17, - 0xdb, 0x4f, 0x1b, 0x54, 0x34, 0xdb, 0x35, 0xb3, 0xce, 0x82, 0xe2, 0xd8, 0xd5, 0x1c, 0x3d, 0xde, - 0xab, 0x37, 0x1d, 0x1a, 0x16, 0xb3, 0x88, 0x2b, 0x3a, 0x11, 0x72, 0xb3, 0x8a, 0x31, 0x75, 0x7c, - 0x7a, 0xe2, 0xd4, 0x7c, 0x3c, 0x08, 0x85, 0xb5, 0x3e, 0x10, 0x38, 0x4c, 0xf8, 0x49, 0x00, 0x79, - 0x2e, 0x9c, 0xcf, 0xe8, 0xda, 0x4e, 0xc0, 0xda, 0xa1, 0x50, 0x97, 0xff, 0xb3, 0xe0, 0x5a, 0x4a, - 0x5f, 0x4e, 0xd8, 0x8d, 0x17, 0xb0, 0x61, 0xc9, 0x06, 0x2a, 0x9d, 0x7f, 0xf1, 0xe8, 0x23, 0x90, - 0x51, 0x22, 0xe9, 0xcf, 0x73, 0xd8, 0xc8, 0x26, 0xc3, 0x9e, 0x95, 0xf3, 0x56, 0x56, 0x22, 0xe3, - 0x86, 0x06, 0x6a, 0xd9, 0xf7, 0xb3, 0x11, 0x78, 0x47, 0x31, 0xe6, 0xb2, 0x59, 0xe3, 0x13, 0x6c, - 0x5d, 0x82, 0x49, 0xfd, 0x67, 0xb0, 0xdc, 0x37, 0x3b, 0xd5, 0x5c, 0x2d, 0x3d, 0x30, 0xa7, 0x6c, - 0x82, 0x39, 0x5e, 0x5f, 0x59, 0xea, 0x5f, 0xb7, 0x95, 0xd6, 0x1a, 0x77, 0x61, 0x2b, 0x83, 0xb3, - 0xa9, 0x1a, 0xc8, 0x07, 0xa0, 0x5d, 0x06, 0x4a, 0xfd, 0xd7, 0xb0, 0x92, 0x0d, 0xa7, 0xec, 0x61, - 0xf7, 0xea, 0x1e, 0x32, 0x1e, 0xd9, 0xc7, 0x90, 0xa3, 0xf4, 0x73, 0x11, 0x96, 0xdf, 0xf6, 0x57, - 0x9b, 0x84, 0x90, 0x1f, 0xdb, 0x09, 0xb2, 0x77, 0x35, 0xf1, 0xc8, 0x22, 0x6a, 0xe6, 0xac, 0xe9, - 0xf2, 0x57, 0x10, 0x60, 0x68, 0x30, 0x79, 0x38, 0xb5, 0x7a, 0x62, 0x9c, 0xb4, 0xdd, 0x99, 0x72, - 0xa5, 0xcc, 0x09, 0x6c, 0x4c, 0xd8, 0x49, 0x1e, 0x4d, 0xef, 0x75, 0xca, 0x58, 0x68, 0xa5, 0x79, - 0x4a, 0xa4, 0xf6, 0x57, 0x20, 0x93, 0x1e, 0x90, 0xd2, 0x1c, 0x86, 0x0d, 0xd4, 0xf7, 0xe7, 0xaa, - 0x49, 0xe5, 0x2b, 0x87, 0xa7, 0x5d, 0x5d, 0x39, 0xeb, 0xea, 0xca, 0xef, 0xae, 0xae, 0x7c, 0xeb, - 0xe9, 0xb9, 0xb3, 0x9e, 0x9e, 0x3b, 0xef, 0xe9, 0xb9, 0x0f, 0x4f, 0x66, 0xdf, 0xfa, 0xe3, 0xd1, - 0x57, 0x39, 0x79, 0x01, 0x6a, 0xd7, 0x12, 0x70, 0xff, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfa, - 0xb5, 0x23, 0xef, 0x2c, 0x06, 0x00, 0x00, + // 672 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcb, 0x6e, 0xd3, 0x40, + 0x14, 0x8d, 0x4b, 0x03, 0x74, 0xda, 0x14, 0x3a, 0x2a, 0xc2, 0x35, 0x28, 0xad, 0x8c, 0x10, 0x11, + 0xa5, 0x36, 0x4d, 0x2b, 0x24, 0x24, 0x16, 0x24, 0x08, 0x41, 0xd9, 0x00, 0x2e, 0x2a, 0x12, 0x2c, + 0x8c, 0x13, 0x5f, 0x27, 0x23, 0x6c, 0x8f, 0xeb, 0x99, 0x94, 0x06, 0xc4, 0x86, 0x2f, 0x40, 0x62, + 0xcd, 0x07, 0xb0, 0x43, 0x82, 0x25, 0x1f, 0xd0, 0x65, 0x05, 0x9b, 0x8a, 0x45, 0x85, 0x5a, 0x3e, + 0x04, 0x65, 0x3c, 0x71, 0x52, 0x5a, 0xab, 0x89, 0x60, 0x37, 0xbe, 0x8f, 0x73, 0x8e, 0xef, 0x9c, + 0x3b, 0xe8, 0x92, 0xdb, 0x76, 0x37, 0xa3, 0x98, 0x72, 0x5a, 0xa7, 0xbe, 0xe9, 0x78, 0x1e, 0xf1, + 0x89, 0xc3, 0x81, 0x99, 0xeb, 0x2d, 0x88, 0xdb, 0x86, 0xc8, 0xe0, 0xf3, 0xfd, 0x45, 0x46, 0xaf, + 0x48, 0x9b, 0xa9, 0x53, 0x16, 0x50, 0x66, 0x8b, 0x9c, 0x99, 0x7c, 0x24, 0x3d, 0xda, 0x74, 0x83, + 0x36, 0x68, 0x12, 0xef, 0x9c, 0x64, 0xb4, 0x94, 0x45, 0xd7, 0x3b, 0xca, 0xca, 0x8b, 0x0d, 0x4a, + 0x1b, 0x3e, 0x98, 0x4e, 0x44, 0x4c, 0x27, 0x0c, 0x29, 0x77, 0x38, 0xa1, 0xa1, 0xcc, 0xea, 0x0f, + 0xd0, 0x74, 0xa5, 0xdb, 0xb1, 0x12, 0x7a, 0xd4, 0x82, 0xf5, 0x16, 0x30, 0x8e, 0xcb, 0xe8, 0x94, + 0xe3, 0xba, 0x31, 0x30, 0xa6, 0x2a, 0x73, 0x4a, 0x69, 0xac, 0xaa, 0x7e, 0xff, 0xba, 0x30, 0x2d, + 0x85, 0x55, 0x92, 0xcc, 0x2a, 0x8f, 0x49, 0xd8, 0xb0, 0xba, 0x85, 0xfa, 0xce, 0x08, 0x3a, 0xf7, + 0x17, 0x18, 0x8b, 0x68, 0xc8, 0x00, 0x5f, 0x46, 0x93, 0x84, 0xd9, 0xaf, 0x9a, 0x84, 0x83, 0x4f, + 0x18, 0x07, 0x57, 0x80, 0x9e, 0xb6, 0x0a, 0x84, 0x3d, 0xed, 0x05, 0x31, 0x46, 0xa3, 0x9c, 0x40, + 0xac, 0x8e, 0xcc, 0x29, 0xa5, 0x82, 0x25, 0xce, 0x58, 0x47, 0x05, 0x0f, 0xc0, 0x66, 0x4d, 0x27, + 0x06, 0x3b, 0x8a, 0x02, 0xf5, 0x84, 0x48, 0x8e, 0x7b, 0x00, 0xab, 0x9d, 0xd8, 0xa3, 0x28, 0xc0, + 0xeb, 0xe8, 0x4c, 0x0c, 0x1e, 0xc4, 0x31, 0xb8, 0xf6, 0x06, 0xf5, 0x5b, 0x01, 0xa8, 0xa3, 0x73, + 0x4a, 0x69, 0xa2, 0x7a, 0x7f, 0x6b, 0x77, 0x36, 0xf7, 0x73, 0x77, 0xf6, 0x76, 0x83, 0xf0, 0x66, + 0xab, 0x66, 0xd4, 0x69, 0x60, 0x1e, 0x18, 0xdc, 0xc6, 0xf2, 0x42, 0xbd, 0xe9, 0x90, 0xd0, 0x4c, + 0x23, 0x2e, 0x6f, 0x47, 0xc0, 0x8c, 0x55, 0x88, 0x89, 0xe3, 0x93, 0xd7, 0x4e, 0xcd, 0x87, 0x95, + 0x90, 0x5b, 0x93, 0x5d, 0x82, 0x35, 0x81, 0x8f, 0x03, 0x54, 0x60, 0xdc, 0x79, 0x09, 0xae, 0xed, + 0x04, 0xb4, 0x15, 0x72, 0x35, 0xff, 0x9f, 0x09, 0x27, 0x12, 0xf8, 0x8a, 0x40, 0xd7, 0xef, 0xa1, + 0x29, 0x4b, 0x0a, 0xa8, 0xb6, 0xff, 0xe5, 0x8e, 0x9e, 0x23, 0xdc, 0x0f, 0x24, 0xef, 0xe7, 0x2e, + 0x9a, 0x4a, 0x7d, 0x63, 0x0f, 0x8a, 0x79, 0x36, 0x6d, 0x91, 0x71, 0x5d, 0x43, 0x6a, 0xc5, 0xf7, + 0x53, 0x0b, 0x3c, 0x21, 0x10, 0x33, 0x29, 0x56, 0x7f, 0x81, 0x66, 0x8e, 0xc8, 0x49, 0xfe, 0x3b, + 0x28, 0xdf, 0xb9, 0xec, 0x84, 0x73, 0xbc, 0x7c, 0xc5, 0xc8, 0xd8, 0x13, 0xe3, 0x60, 0x7f, 0x75, + 0xb4, 0x33, 0x6e, 0x2b, 0xe9, 0xd5, 0x2f, 0xa0, 0x99, 0x34, 0x9d, 0xba, 0xaa, 0x4b, 0x1f, 0x20, + 0xed, 0xa8, 0xa4, 0xe4, 0x7f, 0x88, 0xc6, 0x52, 0x73, 0x4a, 0x0d, 0xf3, 0xc7, 0x6b, 0x48, 0x71, + 0xa4, 0x8e, 0x1e, 0x46, 0xf9, 0x5b, 0x1e, 0xe5, 0x1f, 0x77, 0x16, 0x1f, 0x7f, 0x52, 0x50, 0xe1, + 0xc0, 0x52, 0xe0, 0x85, 0xe3, 0x91, 0xfb, 0x36, 0x51, 0x33, 0x06, 0x2d, 0x4f, 0xfe, 0x45, 0xbf, + 0xf9, 0xee, 0xc7, 0xef, 0x0f, 0x23, 0x4b, 0x78, 0xd1, 0x3c, 0xf6, 0x89, 0xb0, 0x49, 0xe8, 0x51, + 0xf3, 0x8d, 0xbc, 0xf0, 0xb7, 0xf8, 0xa3, 0x82, 0x50, 0xcf, 0x1d, 0xf8, 0x6a, 0x26, 0xf3, 0x21, + 0x2f, 0x6a, 0xf3, 0x03, 0xd5, 0x4a, 0x89, 0x37, 0x84, 0xc4, 0xeb, 0xd8, 0xc8, 0x94, 0x98, 0xae, + 0x73, 0xad, 0xdd, 0xa7, 0xef, 0xb3, 0x82, 0xa6, 0x0e, 0x99, 0x08, 0x2f, 0x66, 0x0f, 0x28, 0xc3, + 0x8c, 0x5a, 0x79, 0x98, 0x16, 0x29, 0x7a, 0x59, 0x88, 0x36, 0xf0, 0xb5, 0xec, 0xb9, 0xfa, 0xbe, + 0xdd, 0x9b, 0xad, 0x30, 0x25, 0xfe, 0xa2, 0x20, 0x7c, 0xd8, 0x30, 0xb8, 0x3c, 0x84, 0xbb, 0xba, + 0xa2, 0x97, 0x86, 0xea, 0x19, 0x5c, 0x75, 0xaa, 0x38, 0xb5, 0x6f, 0x75, 0x6d, 0x6b, 0xaf, 0xa8, + 0x6c, 0xef, 0x15, 0x95, 0x5f, 0x7b, 0x45, 0xe5, 0xfd, 0x7e, 0x31, 0xb7, 0xbd, 0x5f, 0xcc, 0xed, + 0xec, 0x17, 0x73, 0xcf, 0x6e, 0x0d, 0xfe, 0xb0, 0x6d, 0xf6, 0xb3, 0x88, 0x47, 0xae, 0x76, 0x52, + 0x24, 0x97, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x0e, 0x60, 0x8f, 0x2d, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/protocol/x/affiliates/types/query.pb.gw.go b/protocol/x/affiliates/types/query.pb.gw.go new file mode 100644 index 0000000000..dfd8a2f41c --- /dev/null +++ b/protocol/x/affiliates/types/query.pb.gw.go @@ -0,0 +1,420 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: dydxprotocol/affiliates/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_AffiliateInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AffiliateInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := client.AffiliateInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AffiliateInfo_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AffiliateInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := server.AffiliateInfo(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_ReferredBy_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ReferredByRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := client.ReferredBy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ReferredBy_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ReferredByRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := server.ReferredBy(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_AllAffiliateTiers_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AllAffiliateTiersRequest + var metadata runtime.ServerMetadata + + msg, err := client.AllAffiliateTiers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllAffiliateTiers_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AllAffiliateTiersRequest + var metadata runtime.ServerMetadata + + msg, err := server.AllAffiliateTiers(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_AffiliateWhitelist_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AffiliateWhitelistRequest + var metadata runtime.ServerMetadata + + msg, err := client.AffiliateWhitelist(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AffiliateWhitelist_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AffiliateWhitelistRequest + var metadata runtime.ServerMetadata + + msg, err := server.AffiliateWhitelist(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_AffiliateInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AffiliateInfo_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AffiliateInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ReferredBy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ReferredBy_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ReferredBy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllAffiliateTiers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllAffiliateTiers_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllAffiliateTiers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AffiliateWhitelist_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AffiliateWhitelist_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AffiliateWhitelist_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_AffiliateInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AffiliateInfo_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AffiliateInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ReferredBy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ReferredBy_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ReferredBy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllAffiliateTiers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllAffiliateTiers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllAffiliateTiers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AffiliateWhitelist_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AffiliateWhitelist_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AffiliateWhitelist_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_AffiliateInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"dydxprotocol", "affiliates", "affiliate_info", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ReferredBy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"dydxprotocol", "affiliates", "referred_by", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllAffiliateTiers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "affiliates", "all_affiliate_tiers"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AffiliateWhitelist_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"dydxprotocol", "affiliates", "affiliate_whitelist"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_AffiliateInfo_0 = runtime.ForwardResponseMessage + + forward_Query_ReferredBy_0 = runtime.ForwardResponseMessage + + forward_Query_AllAffiliateTiers_0 = runtime.ForwardResponseMessage + + forward_Query_AffiliateWhitelist_0 = runtime.ForwardResponseMessage +) From d1c8ed8fc11e4418db0826bba8eb02dcc5e97472 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Wed, 6 Nov 2024 03:31:55 -0500 Subject: [PATCH 107/120] Bump Comet version (#2556) --- protocol/go.mod | 2 +- protocol/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/go.mod b/protocol/go.mod index 2ea2c9af98..3abdb94611 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -468,7 +468,7 @@ 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.20241001172045-cfee87f3abbf + github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20241106081823-31609289f401 // 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/iavl => github.com/dydxprotocol/iavl v1.1.1-0.20240509161911-1c8b8e787e85 diff --git a/protocol/go.sum b/protocol/go.sum index e787715efe..647abaad46 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -959,8 +959,8 @@ 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.20241001172045-cfee87f3abbf h1:pdKqF/qshVtVxcCfpK93QSUIIV3UjR/zj0RfPuqFPwU= -github.com/dydxprotocol/cometbft v0.38.6-0.20241001172045-cfee87f3abbf/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= +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/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d h1:HgLu1FD2oDFzlKW6/+SFXlH5Os8cwNTbplQIrQOWx8w= From f1bbac65194ae5b353c95194bff60c750e172173 Mon Sep 17 00:00:00 2001 From: v0-e <134806759+v0-e@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:16:54 +0000 Subject: [PATCH 108/120] Update Rust protos, dependencies enhancements (#2538) --- v4-proto-rs/Cargo.toml | 21 +- v4-proto-rs/README.md | 2 +- v4-proto-rs/build.rs | 75 +- v4-proto-rs/src/_includes.rs | 12 + v4-proto-rs/src/cosmos.base.query.v1beta1.rs | 2 - v4-proto-rs/src/cosmos.base.v1beta1.rs | 4 - v4-proto-rs/src/cosmos_proto.rs | 8 +- v4-proto-rs/src/dydxprotocol.accountplus.rs | 713 +++++++ v4-proto-rs/src/dydxprotocol.affiliates.rs | 734 ++++++++ v4-proto-rs/src/dydxprotocol.assets.rs | 44 +- v4-proto-rs/src/dydxprotocol.blocktime.rs | 69 +- v4-proto-rs/src/dydxprotocol.bridge.rs | 126 +- v4-proto-rs/src/dydxprotocol.clob.rs | 502 ++--- .../src/dydxprotocol.daemons.bridge.rs | 22 +- .../src/dydxprotocol.daemons.liquidation.rs | 22 +- .../src/dydxprotocol.daemons.pricefeed.rs | 24 +- v4-proto-rs/src/dydxprotocol.delaymsg.rs | 63 +- v4-proto-rs/src/dydxprotocol.epochs.rs | 27 +- v4-proto-rs/src/dydxprotocol.feetiers.rs | 52 +- v4-proto-rs/src/dydxprotocol.govplus.rs | 40 +- .../src/dydxprotocol.indexer.events.rs | 106 +- .../dydxprotocol.indexer.indexer_manager.rs | 13 +- .../dydxprotocol.indexer.off_chain_updates.rs | 33 +- .../src/dydxprotocol.indexer.protocol.v1.rs | 89 +- v4-proto-rs/src/dydxprotocol.indexer.redis.rs | 7 +- .../src/dydxprotocol.indexer.shared.rs | 38 +- v4-proto-rs/src/dydxprotocol.indexer.socks.rs | 42 +- v4-proto-rs/src/dydxprotocol.listing.rs | 538 ++++++ v4-proto-rs/src/dydxprotocol.perpetuals.rs | 123 +- v4-proto-rs/src/dydxprotocol.prices.rs | 95 +- v4-proto-rs/src/dydxprotocol.ratelimit.rs | 62 +- v4-proto-rs/src/dydxprotocol.revshare.rs | 671 +++++++ v4-proto-rs/src/dydxprotocol.rewards.rs | 47 +- v4-proto-rs/src/dydxprotocol.sending.rs | 62 +- v4-proto-rs/src/dydxprotocol.stats.rs | 111 +- v4-proto-rs/src/dydxprotocol.subaccounts.rs | 125 +- v4-proto-rs/src/dydxprotocol.vault.rs | 1643 +++++++++++++---- v4-proto-rs/src/dydxprotocol.vest.rs | 51 +- v4-proto-rs/src/google.api.rs | 4 - v4-proto-rs/src/lib.rs | 9 +- 40 files changed, 5137 insertions(+), 1294 deletions(-) create mode 100644 v4-proto-rs/src/dydxprotocol.accountplus.rs create mode 100644 v4-proto-rs/src/dydxprotocol.affiliates.rs create mode 100644 v4-proto-rs/src/dydxprotocol.listing.rs create mode 100644 v4-proto-rs/src/dydxprotocol.revshare.rs diff --git a/v4-proto-rs/Cargo.toml b/v4-proto-rs/Cargo.toml index 8c2e82dd60..3c91472dd4 100644 --- a/v4-proto-rs/Cargo.toml +++ b/v4-proto-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dydx-proto" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Compiled dYdX protobuf files" repository = "https://github.com/dydxprotocol/v4-chain/tree/main/v4-proto-rs" @@ -9,13 +9,18 @@ license = "LicenseRef-dYdX-Custom" [lib] doctest = false +[features] +default = ["grpc-transport"] +grpc-transport = ["tonic/transport"] + [dependencies] -cosmos-sdk-proto = "0.21.1" -tonic = { version = "0.11", features = ["tls", "tls-roots", "transport", "channel"] } -prost = "0.12" -prost-types = "0.12" +cosmos-sdk-proto = { version = "0.26", default-features = false, features = ["grpc"] } +prost = { version = "0.13", default-features = false } +prost-types = "0.13" +tonic = { version = "0.12", default-features = false, features = ["codegen", "prost"] } [build-dependencies] -tonic-buf-build = "0.2.1" -prost-build = "0.12" # keep the version the same as in tonic-buf-build -tonic-build = "0.11" # keep the version the same as in tonic-buf-build +regex = "1.11.1" +tonic-buf-build = "0.3.0" +prost-build = "0.13" # keep the version the same as in tonic-buf-build +tonic-build = "0.12" # keep the version the same as in tonic-buf-build diff --git a/v4-proto-rs/README.md b/v4-proto-rs/README.md index 9f95646255..911a676723 100644 --- a/v4-proto-rs/README.md +++ b/v4-proto-rs/README.md @@ -6,7 +6,7 @@ Cargo.toml ```toml [dependencies] -dydx-proto = "0.1" +dydx-proto = "0.2" ``` *Note:* by default, rust stub files are not rebuilt (see Q&A below) diff --git a/v4-proto-rs/build.rs b/v4-proto-rs/build.rs index dfad90ed8c..01faebdb11 100644 --- a/v4-proto-rs/build.rs +++ b/v4-proto-rs/build.rs @@ -1,28 +1,59 @@ use prost_build::Config; +use regex::Regex; use std::env; -use std::path::PathBuf; - -fn main() -> Result<(), tonic_buf_build::error::TonicBufBuildError> { - if std::env::var("V4_PROTO_REBUILD").is_ok() { - let mut config = Config::new(); - config.out_dir("src"); - config.include_file("_includes.rs"); - config.enable_type_names(); - let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|e| { - tonic_buf_build::error::TonicBufBuildError { - message: format!("Failed to get CARGO_MANIFEST_DIR: {}", e), - cause: None, - } - })?); - path.pop(); - tonic_buf_build::compile_from_buf_workspace_with_config( - tonic_build::configure().build_server(false), - Some(config), - tonic_buf_build::TonicBufConfig { - buf_dir: Some(path), - }, - )?; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +const OUT_DIR: &str = "src"; + +fn features_patch(dir: impl AsRef) -> io::Result<()> { + let regex = "impl(.+)tonic::transport(.+)"; + let replacement = "#[cfg(feature = \"grpc-transport\")]\n \ + impl${1}tonic::transport${2}"; + + let paths = fs::read_dir(dir)?; + + for entry in paths { + let path = entry?.path(); + let mut contents = fs::read_to_string(&path)?; + + contents = Regex::new(regex) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))? + .replace_all(&contents, replacement) + .to_string(); + + fs::write(&path, &contents)? } Ok(()) } + +fn main() -> Result<(), Box> { + if !std::env::var("V4_PROTO_REBUILD").is_ok() { + return Ok(()); + } + + let mut config = Config::new(); + config.out_dir(OUT_DIR); + config.include_file("_includes.rs"); + config.enable_type_names(); + let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|e| { + tonic_buf_build::error::TonicBufBuildError { + message: format!("Failed to get CARGO_MANIFEST_DIR: {}", e), + cause: None, + } + })?); + path.pop(); + tonic_buf_build::compile_from_buf_workspace_with_config( + tonic_build::configure().build_server(false), + Some(config), + tonic_buf_build::TonicBufConfig { + buf_dir: Some(path), + }, + )?; + + features_patch(OUT_DIR)?; + + Ok(()) +} diff --git a/v4-proto-rs/src/_includes.rs b/v4-proto-rs/src/_includes.rs index edcb46e6a8..67c39ce08d 100644 --- a/v4-proto-rs/src/_includes.rs +++ b/v4-proto-rs/src/_includes.rs @@ -15,6 +15,12 @@ pub mod cosmos_proto { include!("cosmos_proto.rs"); } pub mod dydxprotocol { + pub mod accountplus { + include!("dydxprotocol.accountplus.rs"); + } + pub mod affiliates { + include!("dydxprotocol.affiliates.rs"); + } pub mod assets { include!("dydxprotocol.assets.rs"); } @@ -75,6 +81,9 @@ pub mod dydxprotocol { include!("dydxprotocol.indexer.socks.rs"); } } + pub mod listing { + include!("dydxprotocol.listing.rs"); + } pub mod perpetuals { include!("dydxprotocol.perpetuals.rs"); } @@ -84,6 +93,9 @@ pub mod dydxprotocol { pub mod ratelimit { include!("dydxprotocol.ratelimit.rs"); } + pub mod revshare { + include!("dydxprotocol.revshare.rs"); + } pub mod rewards { include!("dydxprotocol.rewards.rs"); } diff --git a/v4-proto-rs/src/cosmos.base.query.v1beta1.rs b/v4-proto-rs/src/cosmos.base.query.v1beta1.rs index dc11f529f4..8ff320df95 100644 --- a/v4-proto-rs/src/cosmos.base.query.v1beta1.rs +++ b/v4-proto-rs/src/cosmos.base.query.v1beta1.rs @@ -6,7 +6,6 @@ /// Foo some_parameter = 1; /// PageRequest pagination = 2; /// } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PageRequest { /// key is a value returned in PageResponse.next_key to begin @@ -52,7 +51,6 @@ impl ::prost::Name for PageRequest { /// repeated Bar results = 1; /// PageResponse page = 2; /// } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PageResponse { /// next_key is the key to be passed to PageRequest.key to diff --git a/v4-proto-rs/src/cosmos.base.v1beta1.rs b/v4-proto-rs/src/cosmos.base.v1beta1.rs index 8a61cfab7a..1c10d66da1 100644 --- a/v4-proto-rs/src/cosmos.base.v1beta1.rs +++ b/v4-proto-rs/src/cosmos.base.v1beta1.rs @@ -3,7 +3,6 @@ /// /// NOTE: The amount field is an Int which implements the custom method /// signatures required by gogoproto. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Coin { #[prost(string, tag = "1")] @@ -25,7 +24,6 @@ impl ::prost::Name for Coin { /// /// NOTE: The amount field is an Dec which implements the custom method /// signatures required by gogoproto. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DecCoin { #[prost(string, tag = "1")] @@ -45,7 +43,6 @@ impl ::prost::Name for DecCoin { } /// IntProto defines a Protobuf wrapper around an Int object. /// Deprecated: Prefer to use math.Int directly. It supports binary Marshal and Unmarshal. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IntProto { #[prost(string, tag = "1")] @@ -63,7 +60,6 @@ impl ::prost::Name for IntProto { } /// DecProto defines a Protobuf wrapper around a Dec object. /// Deprecated: Prefer to use math.LegacyDec directly. It supports binary Marshal and Unmarshal. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DecProto { #[prost(string, tag = "1")] diff --git a/v4-proto-rs/src/cosmos_proto.rs b/v4-proto-rs/src/cosmos_proto.rs index e45172e7ee..9057ec92dd 100644 --- a/v4-proto-rs/src/cosmos_proto.rs +++ b/v4-proto-rs/src/cosmos_proto.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// InterfaceDescriptor describes an interface type to be used with /// accepts_interface and implements_interface and declared by declare_interface. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct InterfaceDescriptor { /// name is the name of the interface. It should be a short-name (without @@ -32,7 +31,6 @@ impl ::prost::Name for InterfaceDescriptor { /// Scalars should ideally define an encoding such that there is only one /// valid syntactical representation for a given semantic meaning, /// i.e. the encoding should be deterministic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ScalarDescriptor { /// name is the name of the scalar. It should be a short-name (without @@ -77,9 +75,9 @@ impl ScalarType { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - ScalarType::Unspecified => "SCALAR_TYPE_UNSPECIFIED", - ScalarType::String => "SCALAR_TYPE_STRING", - ScalarType::Bytes => "SCALAR_TYPE_BYTES", + Self::Unspecified => "SCALAR_TYPE_UNSPECIFIED", + Self::String => "SCALAR_TYPE_STRING", + Self::Bytes => "SCALAR_TYPE_BYTES", } } /// Creates an enum from field names used in the ProtoBuf definition. diff --git a/v4-proto-rs/src/dydxprotocol.accountplus.rs b/v4-proto-rs/src/dydxprotocol.accountplus.rs new file mode 100644 index 0000000000..66c3177c2e --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.accountplus.rs @@ -0,0 +1,713 @@ +// This file is @generated by prost-build. +/// Account State +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountState { + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub timestamp_nonce_details: ::core::option::Option, +} +impl ::prost::Name for AccountState { + const NAME: &'static str = "AccountState"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.AccountState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.AccountState".into() + } +} +/// Timestamp nonce details +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TimestampNonceDetails { + /// unsorted list of n most recent timestamp nonces + #[prost(uint64, repeated, tag = "1")] + pub timestamp_nonces: ::prost::alloc::vec::Vec, + /// max timestamp nonce that was ejected from list above + #[prost(uint64, tag = "2")] + pub max_ejected_nonce: u64, +} +impl ::prost::Name for TimestampNonceDetails { + const NAME: &'static str = "TimestampNonceDetails"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.TimestampNonceDetails".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.TimestampNonceDetails".into() + } +} +/// AccountAuthenticator represents a foundational model for all authenticators. +/// It provides extensibility by allowing concrete types to interpret and +/// validate transactions based on the encapsulated data. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountAuthenticator { + /// ID uniquely identifies the authenticator instance. + #[prost(uint64, tag = "1")] + pub id: u64, + /// Type specifies the category of the AccountAuthenticator. + /// This type information is essential for differentiating authenticators + /// and ensuring precise data retrieval from the storage layer. + #[prost(string, tag = "2")] + pub r#type: ::prost::alloc::string::String, + /// Config is a versatile field used in conjunction with the specific type of + /// account authenticator to facilitate complex authentication processes. + /// The interpretation of this field is overloaded, enabling multiple + /// authenticators to utilize it for their respective purposes. + #[prost(bytes = "vec", tag = "3")] + pub config: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AccountAuthenticator { + const NAME: &'static str = "AccountAuthenticator"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.AccountAuthenticator".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.AccountAuthenticator".into() + } +} +/// Params defines the parameters for the module. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct Params { + /// IsSmartAccountActive defines the state of the authenticator. + /// If set to false, the authenticator module will not be used + /// and the classic cosmos sdk authentication will be used instead. + #[prost(bool, tag = "1")] + pub is_smart_account_active: bool, +} +impl ::prost::Name for Params { + const NAME: &'static str = "Params"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.Params".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.Params".into() + } +} +/// AuthenticatorData represents a genesis exported account with Authenticators. +/// The address is used as the key, and the account authenticators are stored in +/// the authenticators field. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuthenticatorData { + /// address is an account address, one address can have many authenticators + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// authenticators are the account's authenticators, these can be multiple + /// types including SignatureVerification, AllOfs, CosmWasmAuthenticators, etc + #[prost(message, repeated, tag = "2")] + pub authenticators: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AuthenticatorData { + const NAME: &'static str = "AuthenticatorData"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.AuthenticatorData".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.AuthenticatorData".into() + } +} +/// Module genesis state +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag = "1")] + pub accounts: ::prost::alloc::vec::Vec, + /// params define the parameters for the authenticator module. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, + /// next_authenticator_id is the next available authenticator ID. + #[prost(uint64, tag = "3")] + pub next_authenticator_id: u64, + /// authenticator_data contains the data for multiple accounts, each with their + /// authenticators. + #[prost(message, repeated, tag = "4")] + pub authenticator_data: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.GenesisState".into() + } +} +/// QueryParamsRequest is request type for the Query/Params RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryParamsRequest {} +impl ::prost::Name for QueryParamsRequest { + const NAME: &'static str = "QueryParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.QueryParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.QueryParamsRequest".into() + } +} +/// QueryParamsResponse is response type for the Query/Params RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryParamsResponse { + /// params holds all the parameters of this module. + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryParamsResponse { + const NAME: &'static str = "QueryParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.QueryParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.QueryParamsResponse".into() + } +} +/// MsgGetAuthenticatorsRequest defines the Msg/GetAuthenticators request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetAuthenticatorsRequest { + #[prost(string, tag = "1")] + pub account: ::prost::alloc::string::String, +} +impl ::prost::Name for GetAuthenticatorsRequest { + const NAME: &'static str = "GetAuthenticatorsRequest"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.GetAuthenticatorsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.GetAuthenticatorsRequest".into() + } +} +/// MsgGetAuthenticatorsResponse defines the Msg/GetAuthenticators response type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetAuthenticatorsResponse { + #[prost(message, repeated, tag = "1")] + pub account_authenticators: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for GetAuthenticatorsResponse { + const NAME: &'static str = "GetAuthenticatorsResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.GetAuthenticatorsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.GetAuthenticatorsResponse".into() + } +} +/// MsgGetAuthenticatorRequest defines the Msg/GetAuthenticator request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetAuthenticatorRequest { + #[prost(string, tag = "1")] + pub account: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub authenticator_id: u64, +} +impl ::prost::Name for GetAuthenticatorRequest { + const NAME: &'static str = "GetAuthenticatorRequest"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.GetAuthenticatorRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.GetAuthenticatorRequest".into() + } +} +/// MsgGetAuthenticatorResponse defines the Msg/GetAuthenticator response type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetAuthenticatorResponse { + #[prost(message, optional, tag = "1")] + pub account_authenticator: ::core::option::Option, +} +impl ::prost::Name for GetAuthenticatorResponse { + const NAME: &'static str = "GetAuthenticatorResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.GetAuthenticatorResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.GetAuthenticatorResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Parameters queries the parameters of the module. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.accountplus.Query", "Params")); + self.inner.unary(req, path, codec).await + } + /// Queries a single authenticator by account and authenticator ID. + pub async fn get_authenticator( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Query/GetAuthenticator", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.accountplus.Query", "GetAuthenticator"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries all authenticators for a given account. + pub async fn get_authenticators( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Query/GetAuthenticators", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.accountplus.Query", + "GetAuthenticators", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgAddAuthenticatorRequest defines the Msg/AddAuthenticator request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAddAuthenticator { + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub authenticator_type: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "3")] + pub data: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgAddAuthenticator { + const NAME: &'static str = "MsgAddAuthenticator"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgAddAuthenticator".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgAddAuthenticator".into() + } +} +/// MsgAddAuthenticatorResponse defines the Msg/AddAuthenticator response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgAddAuthenticatorResponse { + #[prost(bool, tag = "1")] + pub success: bool, +} +impl ::prost::Name for MsgAddAuthenticatorResponse { + const NAME: &'static str = "MsgAddAuthenticatorResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgAddAuthenticatorResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgAddAuthenticatorResponse".into() + } +} +/// MsgRemoveAuthenticatorRequest defines the Msg/RemoveAuthenticator request +/// type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRemoveAuthenticator { + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub id: u64, +} +impl ::prost::Name for MsgRemoveAuthenticator { + const NAME: &'static str = "MsgRemoveAuthenticator"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgRemoveAuthenticator".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgRemoveAuthenticator".into() + } +} +/// MsgRemoveAuthenticatorResponse defines the Msg/RemoveAuthenticator response +/// type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgRemoveAuthenticatorResponse { + #[prost(bool, tag = "1")] + pub success: bool, +} +impl ::prost::Name for MsgRemoveAuthenticatorResponse { + const NAME: &'static str = "MsgRemoveAuthenticatorResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgRemoveAuthenticatorResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgRemoveAuthenticatorResponse".into() + } +} +/// MsgSetActiveState sets the active state of the module. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetActiveState { + /// Authority is the address that may send this message. + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + #[prost(bool, tag = "2")] + pub active: bool, +} +impl ::prost::Name for MsgSetActiveState { + const NAME: &'static str = "MsgSetActiveState"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgSetActiveState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgSetActiveState".into() + } +} +/// MsgSetActiveStateResponse defines the Msg/SetActiveState response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetActiveStateResponse {} +impl ::prost::Name for MsgSetActiveStateResponse { + const NAME: &'static str = "MsgSetActiveStateResponse"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.MsgSetActiveStateResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.MsgSetActiveStateResponse".into() + } +} +/// TxExtension allows for additional authenticator-specific data in +/// transactions. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TxExtension { + /// selected_authenticators holds the authenticator_id for the chosen + /// authenticator per message. + #[prost(uint64, repeated, tag = "1")] + pub selected_authenticators: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for TxExtension { + const NAME: &'static str = "TxExtension"; + const PACKAGE: &'static str = "dydxprotocol.accountplus"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.accountplus.TxExtension".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.accountplus.TxExtension".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// AddAuthenticator adds an authenticator to an account. + pub async fn add_authenticator( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Msg/AddAuthenticator", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.accountplus.Msg", "AddAuthenticator"), + ); + self.inner.unary(req, path, codec).await + } + /// RemoveAuthenticator removes an authenticator from an account. + pub async fn remove_authenticator( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Msg/RemoveAuthenticator", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.accountplus.Msg", + "RemoveAuthenticator", + ), + ); + self.inner.unary(req, path, codec).await + } + /// SetActiveState sets the active state of the authenticator. + /// Primarily used for circuit breaking. + pub async fn set_active_state( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.accountplus.Msg/SetActiveState", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.accountplus.Msg", "SetActiveState"), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.affiliates.rs b/v4-proto-rs/src/dydxprotocol.affiliates.rs new file mode 100644 index 0000000000..48e1db0064 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.affiliates.rs @@ -0,0 +1,734 @@ +// This file is @generated by prost-build. +/// AffiliateTiers defines the affiliate tiers. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AffiliateTiers { + /// All affiliate tiers + #[prost(message, repeated, tag = "1")] + pub tiers: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `AffiliateTiers`. +pub mod affiliate_tiers { + /// Tier defines an affiliate tier. + #[derive(Clone, Copy, PartialEq, ::prost::Message)] + pub struct Tier { + /// Required all-time referred volume in quote quantums. + #[prost(uint64, tag = "1")] + pub req_referred_volume_quote_quantums: u64, + /// Required currently staked native tokens (in whole coins). + #[prost(uint32, tag = "2")] + pub req_staked_whole_coins: u32, + /// Taker fee share in parts-per-million. + #[prost(uint32, tag = "3")] + pub taker_fee_share_ppm: u32, + } + impl ::prost::Name for Tier { + const NAME: &'static str = "Tier"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateTiers.Tier".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateTiers.Tier".into() + } + } +} +impl ::prost::Name for AffiliateTiers { + const NAME: &'static str = "AffiliateTiers"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateTiers".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateTiers".into() + } +} +/// AffiliateWhitelist specifies the whitelisted affiliates. +/// If an address is in the whitelist, then the affiliate fee share in +/// this object will override fee share from the regular affiliate tiers above. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AffiliateWhitelist { + /// All affiliate whitelist tiers. + #[prost(message, repeated, tag = "1")] + pub tiers: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `AffiliateWhitelist`. +pub mod affiliate_whitelist { + /// Tier defines an affiliate whitelist tier. + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Tier { + /// List of unique whitelisted addresses. + #[prost(string, repeated, tag = "1")] + pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// Taker fee share in parts-per-million. + #[prost(uint32, tag = "2")] + pub taker_fee_share_ppm: u32, + } + impl ::prost::Name for Tier { + const NAME: &'static str = "Tier"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateWhitelist.Tier".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateWhitelist.Tier".into() + } + } +} +impl ::prost::Name for AffiliateWhitelist { + const NAME: &'static str = "AffiliateWhitelist"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateWhitelist".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateWhitelist".into() + } +} +/// GenesisState defines generis state of `x/affiliates` +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// The list of affiliate tiers + #[prost(message, optional, tag = "1")] + pub affiliate_tiers: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.GenesisState".into() + } +} +/// AffiliateInfoRequest is the request type for the Query/AffiliateInfo RPC +/// method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AffiliateInfoRequest { + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +impl ::prost::Name for AffiliateInfoRequest { + const NAME: &'static str = "AffiliateInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateInfoRequest".into() + } +} +/// AffiliateInfoResponse is the response type for the Query/AffiliateInfo RPC +/// method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AffiliateInfoResponse { + /// Whether the address is a whitelisted affiliate (VIP). + #[prost(bool, tag = "1")] + pub is_whitelisted: bool, + /// If `is_whiteslisted == false`, the affiliate's tier qualified through + /// regular affiliate program. + #[prost(uint32, tag = "2")] + pub tier: u32, + /// The affiliate's taker fee share in parts-per-million (for both VIP and + /// regular affiliate). + #[prost(uint32, tag = "3")] + pub fee_share_ppm: u32, + /// The affiliate's all-time referred volume in quote quantums. + #[prost(bytes = "vec", tag = "4")] + pub referred_volume: ::prost::alloc::vec::Vec, + /// The affiliate's currently staked native tokens (in whole coins). + #[prost(bytes = "vec", tag = "5")] + pub staked_amount: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AffiliateInfoResponse { + const NAME: &'static str = "AffiliateInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateInfoResponse".into() + } +} +/// ReferredByRequest is the request type for the Query/ReferredBy RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReferredByRequest { + /// The address to query. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +impl ::prost::Name for ReferredByRequest { + const NAME: &'static str = "ReferredByRequest"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.ReferredByRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.ReferredByRequest".into() + } +} +/// ReferredByResponse is the response type for the Query/ReferredBy RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReferredByResponse { + /// The affiliate's address that referred the queried address. + #[prost(string, tag = "1")] + pub affiliate_address: ::prost::alloc::string::String, +} +impl ::prost::Name for ReferredByResponse { + const NAME: &'static str = "ReferredByResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.ReferredByResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.ReferredByResponse".into() + } +} +/// AllAffiliateTiersRequest is the request type for the Query/AllAffiliateTiers +/// RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct AllAffiliateTiersRequest {} +impl ::prost::Name for AllAffiliateTiersRequest { + const NAME: &'static str = "AllAffiliateTiersRequest"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AllAffiliateTiersRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AllAffiliateTiersRequest".into() + } +} +/// AllAffiliateTiersResponse is the response type for the +/// Query/AllAffiliateTiers RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AllAffiliateTiersResponse { + /// All affiliate tiers information. + #[prost(message, optional, tag = "1")] + pub tiers: ::core::option::Option, +} +impl ::prost::Name for AllAffiliateTiersResponse { + const NAME: &'static str = "AllAffiliateTiersResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AllAffiliateTiersResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AllAffiliateTiersResponse".into() + } +} +/// AffiliateWhitelistRequest is the request type for the +/// Query/AffiliateWhitelist RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct AffiliateWhitelistRequest {} +impl ::prost::Name for AffiliateWhitelistRequest { + const NAME: &'static str = "AffiliateWhitelistRequest"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateWhitelistRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateWhitelistRequest".into() + } +} +/// AffiliateWhitelistResponse is the response type for the +/// Query/AffiliateWhitelist RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AffiliateWhitelistResponse { + #[prost(message, optional, tag = "1")] + pub whitelist: ::core::option::Option, +} +impl ::prost::Name for AffiliateWhitelistResponse { + const NAME: &'static str = "AffiliateWhitelistResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.AffiliateWhitelistResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.AffiliateWhitelistResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Query AffiliateInfo returns the affiliate info for a given address. + pub async fn affiliate_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Query/AffiliateInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.affiliates.Query", "AffiliateInfo"), + ); + self.inner.unary(req, path, codec).await + } + /// Query ReferredBy returns the affiliate that referred a given address. + pub async fn referred_by( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Query/ReferredBy", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.affiliates.Query", "ReferredBy")); + self.inner.unary(req, path, codec).await + } + /// Query AllAffiliateTiers returns all affiliate tiers. + pub async fn all_affiliate_tiers( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Query/AllAffiliateTiers", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.affiliates.Query", "AllAffiliateTiers"), + ); + self.inner.unary(req, path, codec).await + } + /// Query AffiliateWhitelist returns the affiliate whitelist. + pub async fn affiliate_whitelist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Query/AffiliateWhitelist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.affiliates.Query", + "AffiliateWhitelist", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Message to register a referee-affiliate relationship +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterAffiliate { + /// Address of the referee + #[prost(string, tag = "1")] + pub referee: ::prost::alloc::string::String, + /// Address of the affiliate + #[prost(string, tag = "2")] + pub affiliate: ::prost::alloc::string::String, +} +impl ::prost::Name for MsgRegisterAffiliate { + const NAME: &'static str = "MsgRegisterAffiliate"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgRegisterAffiliate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgRegisterAffiliate".into() + } +} +/// Response to MsgRegisterAffiliate +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgRegisterAffiliateResponse {} +impl ::prost::Name for MsgRegisterAffiliateResponse { + const NAME: &'static str = "MsgRegisterAffiliateResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgRegisterAffiliateResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgRegisterAffiliateResponse".into() + } +} +/// Message to update affiliate tiers +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateAffiliateTiers { + /// Authority sending this message. Will be sent by gov + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Updated affiliate tiers information + #[prost(message, optional, tag = "2")] + pub tiers: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateAffiliateTiers { + const NAME: &'static str = "MsgUpdateAffiliateTiers"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgUpdateAffiliateTiers".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgUpdateAffiliateTiers".into() + } +} +/// Response to MsgUpdateAffiliateTiers +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgUpdateAffiliateTiersResponse {} +impl ::prost::Name for MsgUpdateAffiliateTiersResponse { + const NAME: &'static str = "MsgUpdateAffiliateTiersResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgUpdateAffiliateTiersResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgUpdateAffiliateTiersResponse".into() + } +} +/// Message to update affiliate whitelist +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateAffiliateWhitelist { + /// Authority sending this message. Will be sent by gov + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Updated affiliate whitelist information + #[prost(message, optional, tag = "2")] + pub whitelist: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateAffiliateWhitelist { + const NAME: &'static str = "MsgUpdateAffiliateWhitelist"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgUpdateAffiliateWhitelist".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelist".into() + } +} +/// Response to MsgUpdateAffiliateWhitelist +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgUpdateAffiliateWhitelistResponse {} +impl ::prost::Name for MsgUpdateAffiliateWhitelistResponse { + const NAME: &'static str = "MsgUpdateAffiliateWhitelistResponse"; + const PACKAGE: &'static str = "dydxprotocol.affiliates"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.affiliates.MsgUpdateAffiliateWhitelistResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.affiliates.MsgUpdateAffiliateWhitelistResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// RegisterAffiliate registers a referee-affiliate relationship + pub async fn register_affiliate( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Msg/RegisterAffiliate", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.affiliates.Msg", "RegisterAffiliate"), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateAffiliateTiers updates affiliate tiers + pub async fn update_affiliate_tiers( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Msg/UpdateAffiliateTiers", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.affiliates.Msg", + "UpdateAffiliateTiers", + ), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateAffiliateWhitelist updates affiliate whitelist + pub async fn update_affiliate_whitelist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.affiliates.Msg/UpdateAffiliateWhitelist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.affiliates.Msg", + "UpdateAffiliateWhitelist", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.assets.rs b/v4-proto-rs/src/dydxprotocol.assets.rs index 04c175b7d0..b79ee590fd 100644 --- a/v4-proto-rs/src/dydxprotocol.assets.rs +++ b/v4-proto-rs/src/dydxprotocol.assets.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// Asset defines a single exchangable asset. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Asset { /// Unique, sequentially-generated. @@ -51,7 +50,6 @@ impl ::prost::Name for Asset { } } /// GenesisState defines the assets module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, repeated, tag = "1")] @@ -68,8 +66,7 @@ impl ::prost::Name for GenesisState { } } /// Queries an Asset by id. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryAssetRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -85,7 +82,6 @@ impl ::prost::Name for QueryAssetRequest { } } /// QueryAssetResponse is response type for the Asset RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAssetResponse { #[prost(message, optional, tag = "1")] @@ -102,7 +98,6 @@ impl ::prost::Name for QueryAssetResponse { } } /// Queries a list of Asset items. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllAssetsRequest { #[prost(message, optional, tag = "1")] @@ -121,7 +116,6 @@ impl ::prost::Name for QueryAllAssetsRequest { } } /// QueryAllAssetsResponse is response type for the AllAssets RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllAssetsResponse { #[prost(message, repeated, tag = "1")] @@ -143,7 +137,13 @@ impl ::prost::Name for QueryAllAssetsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -151,6 +151,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -166,8 +167,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -192,7 +193,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -239,8 +240,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -265,8 +265,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -283,7 +282,13 @@ pub mod query_client { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -291,6 +296,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -306,8 +312,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -332,7 +338,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } diff --git a/v4-proto-rs/src/dydxprotocol.blocktime.rs b/v4-proto-rs/src/dydxprotocol.blocktime.rs index c92356fc7b..fa804567ec 100644 --- a/v4-proto-rs/src/dydxprotocol.blocktime.rs +++ b/v4-proto-rs/src/dydxprotocol.blocktime.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// BlockInfo stores information about a block -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct BlockInfo { #[prost(uint32, tag = "1")] pub height: u32, @@ -19,7 +18,6 @@ impl ::prost::Name for BlockInfo { } } /// AllDowntimeInfo stores information for all downtime durations. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AllDowntimeInfo { /// The downtime information for each tracked duration. Sorted by duration, @@ -31,8 +29,7 @@ pub struct AllDowntimeInfo { pub mod all_downtime_info { /// Stores information about downtime. block_info corresponds to the most /// recent block at which a downtime occurred. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct DowntimeInfo { #[prost(message, optional, tag = "1")] pub duration: ::core::option::Option<::prost_types::Duration>, @@ -61,7 +58,6 @@ impl ::prost::Name for AllDowntimeInfo { } } /// DowntimeParams defines the parameters for downtime. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DowntimeParams { /// Durations tracked for downtime. The durations must be sorted from @@ -80,7 +76,6 @@ impl ::prost::Name for DowntimeParams { } } /// GenesisState defines the blocktime module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, optional, tag = "1")] @@ -98,8 +93,7 @@ impl ::prost::Name for GenesisState { } /// QueryDowntimeParamsRequest is a request type for the DowntimeParams /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryDowntimeParamsRequest {} impl ::prost::Name for QueryDowntimeParamsRequest { const NAME: &'static str = "QueryDowntimeParamsRequest"; @@ -113,7 +107,6 @@ impl ::prost::Name for QueryDowntimeParamsRequest { } /// QueryDowntimeParamsResponse is a response type for the DowntimeParams /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDowntimeParamsResponse { #[prost(message, optional, tag = "1")] @@ -131,8 +124,7 @@ impl ::prost::Name for QueryDowntimeParamsResponse { } /// QueryPreviousBlockInfoRequest is a request type for the PreviousBlockInfo /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPreviousBlockInfoRequest {} impl ::prost::Name for QueryPreviousBlockInfoRequest { const NAME: &'static str = "QueryPreviousBlockInfoRequest"; @@ -146,8 +138,7 @@ impl ::prost::Name for QueryPreviousBlockInfoRequest { } /// QueryPreviousBlockInfoResponse is a request type for the PreviousBlockInfo /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPreviousBlockInfoResponse { #[prost(message, optional, tag = "1")] pub info: ::core::option::Option, @@ -164,8 +155,7 @@ impl ::prost::Name for QueryPreviousBlockInfoResponse { } /// QueryAllDowntimeInfoRequest is a request type for the AllDowntimeInfo /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryAllDowntimeInfoRequest {} impl ::prost::Name for QueryAllDowntimeInfoRequest { const NAME: &'static str = "QueryAllDowntimeInfoRequest"; @@ -179,7 +169,6 @@ impl ::prost::Name for QueryAllDowntimeInfoRequest { } /// QueryAllDowntimeInfoResponse is a request type for the AllDowntimeInfo /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllDowntimeInfoResponse { #[prost(message, optional, tag = "1")] @@ -197,7 +186,13 @@ impl ::prost::Name for QueryAllDowntimeInfoResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -205,6 +200,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -220,8 +216,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -246,7 +242,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -293,8 +289,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -321,8 +316,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -349,8 +343,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -368,7 +361,6 @@ pub mod query_client { } } /// MsgUpdateDowntimeParams is the Msg/UpdateDowntimeParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateDowntimeParams { #[prost(string, tag = "1")] @@ -389,8 +381,7 @@ impl ::prost::Name for MsgUpdateDowntimeParams { } /// MsgUpdateDowntimeParamsResponse is the Msg/UpdateDowntimeParams response /// type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateDowntimeParamsResponse {} impl ::prost::Name for MsgUpdateDowntimeParamsResponse { const NAME: &'static str = "MsgUpdateDowntimeParamsResponse"; @@ -404,7 +395,13 @@ impl ::prost::Name for MsgUpdateDowntimeParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -412,6 +409,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -427,8 +425,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -453,7 +451,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -500,8 +498,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.bridge.rs b/v4-proto-rs/src/dydxprotocol.bridge.rs index 43d0e28ca0..abea313aca 100644 --- a/v4-proto-rs/src/dydxprotocol.bridge.rs +++ b/v4-proto-rs/src/dydxprotocol.bridge.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// BridgeEvent is a recognized event from the Ethereum blockchain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BridgeEvent { /// The unique id of the Ethereum event log. @@ -28,8 +27,7 @@ impl ::prost::Name for BridgeEvent { } /// BridgeEventInfo stores information about the most recently processed bridge /// event. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct BridgeEventInfo { /// The next event id (the last processed id plus one) of the logs from the /// Ethereum contract. @@ -51,7 +49,6 @@ impl ::prost::Name for BridgeEventInfo { } /// EventParams stores parameters about which events to recognize and which /// tokens to mint. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EventParams { /// The denom of the token to mint. @@ -75,8 +72,7 @@ impl ::prost::Name for EventParams { } } /// ProposeParams stores parameters for proposing to the module. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ProposeParams { /// The maximum number of bridge events to propose per block. /// Limits the number of events to propose in a single block @@ -112,8 +108,7 @@ impl ::prost::Name for ProposeParams { } } /// SafetyParams stores safety parameters for the module. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SafetyParams { /// True if bridging is disabled. #[prost(bool, tag = "1")] @@ -134,7 +129,6 @@ impl ::prost::Name for SafetyParams { } } /// GenesisState defines the bridge module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// The parameters of the module. @@ -161,7 +155,6 @@ impl ::prost::Name for GenesisState { } } /// MsgAcknowledgeBridges is the Msg/AcknowledgeBridges request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgAcknowledgeBridges { /// The events to acknowledge. @@ -180,8 +173,7 @@ impl ::prost::Name for MsgAcknowledgeBridges { } /// MsgAcknowledgeBridgesResponse is the Msg/AcknowledgeBridgesResponse response /// type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgAcknowledgeBridgesResponse {} impl ::prost::Name for MsgAcknowledgeBridgesResponse { const NAME: &'static str = "MsgAcknowledgeBridgesResponse"; @@ -194,7 +186,6 @@ impl ::prost::Name for MsgAcknowledgeBridgesResponse { } } /// MsgCompleteBridge is the Msg/CompleteBridgeResponse request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCompleteBridge { #[prost(string, tag = "1")] @@ -214,8 +205,7 @@ impl ::prost::Name for MsgCompleteBridge { } } /// MsgCompleteBridgeResponse is the Msg/CompleteBridgeResponse response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCompleteBridgeResponse {} impl ::prost::Name for MsgCompleteBridgeResponse { const NAME: &'static str = "MsgCompleteBridgeResponse"; @@ -228,7 +218,6 @@ impl ::prost::Name for MsgCompleteBridgeResponse { } } /// MsgUpdateEventParams is the Msg/UpdateEventParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateEventParams { #[prost(string, tag = "1")] @@ -248,8 +237,7 @@ impl ::prost::Name for MsgUpdateEventParams { } } /// MsgUpdateEventParamsResponse is the Msg/UpdateEventParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateEventParamsResponse {} impl ::prost::Name for MsgUpdateEventParamsResponse { const NAME: &'static str = "MsgUpdateEventParamsResponse"; @@ -262,7 +250,6 @@ impl ::prost::Name for MsgUpdateEventParamsResponse { } } /// MsgUpdateProposeParams is the Msg/UpdateProposeParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateProposeParams { #[prost(string, tag = "1")] @@ -282,8 +269,7 @@ impl ::prost::Name for MsgUpdateProposeParams { } } /// MsgUpdateProposeParamsResponse is the Msg/UpdateProposeParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateProposeParamsResponse {} impl ::prost::Name for MsgUpdateProposeParamsResponse { const NAME: &'static str = "MsgUpdateProposeParamsResponse"; @@ -296,7 +282,6 @@ impl ::prost::Name for MsgUpdateProposeParamsResponse { } } /// MsgUpdateSafetyParams is the Msg/UpdateSafetyParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateSafetyParams { #[prost(string, tag = "1")] @@ -316,8 +301,7 @@ impl ::prost::Name for MsgUpdateSafetyParams { } } /// MsgUpdateSafetyParamsResponse is the Msg/UpdateSafetyParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateSafetyParamsResponse {} impl ::prost::Name for MsgUpdateSafetyParamsResponse { const NAME: &'static str = "MsgUpdateSafetyParamsResponse"; @@ -331,7 +315,13 @@ impl ::prost::Name for MsgUpdateSafetyParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -339,6 +329,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -354,8 +345,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -380,7 +371,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -428,8 +419,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -456,8 +446,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -482,8 +471,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -508,8 +496,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -536,8 +523,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -555,8 +541,7 @@ pub mod msg_client { } } /// QueryEventParamsRequest is a request type for the EventParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryEventParamsRequest {} impl ::prost::Name for QueryEventParamsRequest { const NAME: &'static str = "QueryEventParamsRequest"; @@ -569,7 +554,6 @@ impl ::prost::Name for QueryEventParamsRequest { } } /// QueryEventParamsResponse is a response type for the EventParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryEventParamsResponse { #[prost(message, optional, tag = "1")] @@ -586,8 +570,7 @@ impl ::prost::Name for QueryEventParamsResponse { } } /// QueryProposeParamsRequest is a request type for the ProposeParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryProposeParamsRequest {} impl ::prost::Name for QueryProposeParamsRequest { const NAME: &'static str = "QueryProposeParamsRequest"; @@ -601,8 +584,7 @@ impl ::prost::Name for QueryProposeParamsRequest { } /// QueryProposeParamsResponse is a response type for the ProposeParams RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryProposeParamsResponse { #[prost(message, optional, tag = "1")] pub params: ::core::option::Option, @@ -618,8 +600,7 @@ impl ::prost::Name for QueryProposeParamsResponse { } } /// QuerySafetyParamsRequest is a request type for the SafetyParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QuerySafetyParamsRequest {} impl ::prost::Name for QuerySafetyParamsRequest { const NAME: &'static str = "QuerySafetyParamsRequest"; @@ -632,8 +613,7 @@ impl ::prost::Name for QuerySafetyParamsRequest { } } /// QuerySafetyParamsResponse is a response type for the SafetyParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QuerySafetyParamsResponse { #[prost(message, optional, tag = "1")] pub params: ::core::option::Option, @@ -650,8 +630,7 @@ impl ::prost::Name for QuerySafetyParamsResponse { } /// QueryAcknowledgedEventInfoRequest is a request type for the /// AcknowledgedEventInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryAcknowledgedEventInfoRequest {} impl ::prost::Name for QueryAcknowledgedEventInfoRequest { const NAME: &'static str = "QueryAcknowledgedEventInfoRequest"; @@ -665,8 +644,7 @@ impl ::prost::Name for QueryAcknowledgedEventInfoRequest { } /// QueryAcknowledgedEventInfoResponse is a response type for the /// AcknowledgedEventInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryAcknowledgedEventInfoResponse { #[prost(message, optional, tag = "1")] pub info: ::core::option::Option, @@ -683,8 +661,7 @@ impl ::prost::Name for QueryAcknowledgedEventInfoResponse { } /// QueryRecognizedEventInfoRequest is a request type for the /// RecognizedEventInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryRecognizedEventInfoRequest {} impl ::prost::Name for QueryRecognizedEventInfoRequest { const NAME: &'static str = "QueryRecognizedEventInfoRequest"; @@ -698,8 +675,7 @@ impl ::prost::Name for QueryRecognizedEventInfoRequest { } /// QueryRecognizedEventInfoResponse is a response type for the /// RecognizedEventInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryRecognizedEventInfoResponse { #[prost(message, optional, tag = "1")] pub info: ::core::option::Option, @@ -716,7 +692,6 @@ impl ::prost::Name for QueryRecognizedEventInfoResponse { } /// QueryDelayedCompleteBridgeMessagesRequest is a request type for the /// DelayedCompleteBridgeMessages RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDelayedCompleteBridgeMessagesRequest { #[prost(string, tag = "1")] @@ -734,7 +709,6 @@ impl ::prost::Name for QueryDelayedCompleteBridgeMessagesRequest { } /// QueryDelayedCompleteBridgeMessagesResponse is a response type for the /// DelayedCompleteBridgeMessages RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDelayedCompleteBridgeMessagesResponse { #[prost(message, repeated, tag = "1")] @@ -753,7 +727,6 @@ impl ::prost::Name for QueryDelayedCompleteBridgeMessagesResponse { /// DelayedCompleteBridgeMessage is a message type for the response of /// DelayedCompleteBridgeMessages RPC method. It contains the message /// and the block height at which it will execute. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DelayedCompleteBridgeMessage { #[prost(message, optional, tag = "1")] @@ -773,7 +746,13 @@ impl ::prost::Name for DelayedCompleteBridgeMessage { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -781,6 +760,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -796,8 +776,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -822,7 +802,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -869,8 +849,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -895,8 +874,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -921,8 +899,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -949,8 +926,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -979,8 +955,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1010,8 +985,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.clob.rs b/v4-proto-rs/src/dydxprotocol.clob.rs index c8c7008c1c..153301d78a 100644 --- a/v4-proto-rs/src/dydxprotocol.clob.rs +++ b/v4-proto-rs/src/dydxprotocol.clob.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// Defines the block rate limits for CLOB specific operations. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockRateLimitConfiguration { /// How many short term order attempts (successful and failed) are allowed for @@ -61,8 +60,7 @@ impl ::prost::Name for BlockRateLimitConfiguration { } } /// Defines a rate limit over a specific number of blocks. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MaxPerNBlocksRateLimit { /// How many blocks the rate limit is over. /// Specifying 0 is invalid. @@ -85,8 +83,7 @@ impl ::prost::Name for MaxPerNBlocksRateLimit { } /// PerpetualClobMetadata contains metadata for a `ClobPair` /// representing a Perpetual product. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct PerpetualClobMetadata { /// Id of the Perpetual the CLOB allows trading of. #[prost(uint32, tag = "1")] @@ -104,8 +101,7 @@ impl ::prost::Name for PerpetualClobMetadata { } /// PerpetualClobMetadata contains metadata for a `ClobPair` /// representing a Spot product. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SpotClobMetadata { /// Id of the base Asset in the trading pair. #[prost(uint32, tag = "1")] @@ -126,8 +122,7 @@ impl ::prost::Name for SpotClobMetadata { } /// ClobPair represents a single CLOB pair for a given product /// in state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ClobPair { /// ID of the orderbook that stores all resting liquidity for this CLOB. #[prost(uint32, tag = "1")] @@ -198,13 +193,13 @@ pub mod clob_pair { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Status::Unspecified => "STATUS_UNSPECIFIED", - Status::Active => "STATUS_ACTIVE", - Status::Paused => "STATUS_PAUSED", - Status::CancelOnly => "STATUS_CANCEL_ONLY", - Status::PostOnly => "STATUS_POST_ONLY", - Status::Initializing => "STATUS_INITIALIZING", - Status::FinalSettlement => "STATUS_FINAL_SETTLEMENT", + Self::Unspecified => "STATUS_UNSPECIFIED", + Self::Active => "STATUS_ACTIVE", + Self::Paused => "STATUS_PAUSED", + Self::CancelOnly => "STATUS_CANCEL_ONLY", + Self::PostOnly => "STATUS_POST_ONLY", + Self::Initializing => "STATUS_INITIALIZING", + Self::FinalSettlement => "STATUS_FINAL_SETTLEMENT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -223,8 +218,7 @@ pub mod clob_pair { } /// Product-specific metadata. Perpetual CLOBs will have /// PerpetualClobMetadata, and Spot CLOBs will have SpotClobMetadata. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum Metadata { #[prost(message, tag = "2")] PerpetualClobMetadata(super::PerpetualClobMetadata), @@ -244,7 +238,6 @@ impl ::prost::Name for ClobPair { } /// Defines the set of equity tiers to limit how many open orders /// a subaccount is allowed to have. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EquityTierLimitConfiguration { /// How many short term stateful orders are allowed per equity tier. @@ -267,7 +260,6 @@ impl ::prost::Name for EquityTierLimitConfiguration { } } /// Defines an equity tier limit. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EquityTierLimit { /// The total net collateral in USDC quote quantums of equity required. @@ -287,9 +279,36 @@ impl ::prost::Name for EquityTierLimit { "/dydxprotocol.clob.EquityTierLimit".into() } } +/// ClobStagedFinalizeBlockEvent defines a CLOB event staged during +/// FinalizeBlock. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct ClobStagedFinalizeBlockEvent { + /// event is the staged event. + #[prost(oneof = "clob_staged_finalize_block_event::Event", tags = "1")] + pub event: ::core::option::Option, +} +/// Nested message and enum types in `ClobStagedFinalizeBlockEvent`. +pub mod clob_staged_finalize_block_event { + /// event is the staged event. + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum Event { + /// create_clob_pair indicates a new CLOB pair creation. + #[prost(message, tag = "1")] + CreateClobPair(super::ClobPair), + } +} +impl ::prost::Name for ClobStagedFinalizeBlockEvent { + const NAME: &'static str = "ClobStagedFinalizeBlockEvent"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.ClobStagedFinalizeBlockEvent".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.ClobStagedFinalizeBlockEvent".into() + } +} /// LiquidationsConfig stores all configurable fields related to liquidations. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct LiquidationsConfig { /// The maximum liquidation fee (in parts-per-million). This fee goes /// 100% to the insurance fund. @@ -320,8 +339,7 @@ impl ::prost::Name for LiquidationsConfig { } /// PositionBlockLimits stores all configurable fields related to limits /// around how much of a single position can be liquidated within a single block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct PositionBlockLimits { /// The minimum amount of quantums to liquidate for each message (in /// quote quantums). @@ -346,8 +364,7 @@ impl ::prost::Name for PositionBlockLimits { /// SubaccountBlockLimits stores all configurable fields related to limits /// around how many quote quantums from a single subaccount can /// be liquidated within a single block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SubaccountBlockLimits { /// The maximum notional amount that a single subaccount can have /// liquidated (in quote quantums) per block. @@ -370,8 +387,7 @@ impl ::prost::Name for SubaccountBlockLimits { } /// FillablePriceConfig stores all configurable fields related to calculating /// the fillable price for liquidating a position. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct FillablePriceConfig { /// The rate at which the Adjusted Bankruptcy Rating increases. #[prost(uint32, tag = "1")] @@ -392,7 +408,6 @@ impl ::prost::Name for FillablePriceConfig { } } /// GenesisState defines the clob module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, repeated, tag = "1")] @@ -418,7 +433,6 @@ impl ::prost::Name for GenesisState { /// for a position held by a subaccount. /// Note this proto is defined to make it easier to hash /// the metadata of a liquidation, and is never written to state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualLiquidationInfo { /// The id of the subaccount that got liquidated/deleveraged or was deleveraged @@ -441,7 +455,6 @@ impl ::prost::Name for PerpetualLiquidationInfo { } /// SubaccountLiquidationInfo holds liquidation information per-subaccount in the /// current block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SubaccountLiquidationInfo { /// An unsorted list of unique perpetual IDs that the subaccount has previously @@ -469,7 +482,6 @@ impl ::prost::Name for SubaccountLiquidationInfo { } /// SubaccountOpenPositionInfo holds information about open positions for a /// perpetual. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SubaccountOpenPositionInfo { /// The id of the perpetual. @@ -497,7 +509,6 @@ impl ::prost::Name for SubaccountOpenPositionInfo { } } /// OrderId refers to a single order belonging to a Subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderId { /// The subaccount ID that opened this order. @@ -543,7 +554,6 @@ impl ::prost::Name for OrderId { } /// OrdersFilledDuringLatestBlock represents a list of `OrderIds` that were /// filled by any non-zero amount in the latest block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrdersFilledDuringLatestBlock { /// A list of unique order_ids that were filled by any non-zero amount in the @@ -563,7 +573,6 @@ impl ::prost::Name for OrdersFilledDuringLatestBlock { } /// PotentiallyPrunableOrders represents a list of orders that may be prunable /// from state at a future block height. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PotentiallyPrunableOrders { /// A list of unique order_ids that may potentially be pruned from state at a @@ -585,8 +594,7 @@ impl ::prost::Name for PotentiallyPrunableOrders { /// state. This proto includes both the current on-chain fill amount of the /// order, as well as the block at which this information can be pruned from /// state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct OrderFillState { /// The current fillAmount of the order according to on-chain state. #[prost(uint64, tag = "1")] @@ -614,7 +622,6 @@ impl ::prost::Name for OrderFillState { /// This `StatefulOrderTimeSliceValue` in state is used for managing stateful /// order expiration. Stateful order expirations can be for either long term /// or conditional orders. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StatefulOrderTimeSliceValue { /// A unique list of order_ids that expire at this timestamp, sorted in @@ -636,7 +643,6 @@ impl ::prost::Name for StatefulOrderTimeSliceValue { /// LongTermOrderPlacement represents the placement of a stateful order in /// state. It stores the stateful order itself and the `BlockHeight` and /// `TransactionIndex` at which the order was placed. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LongTermOrderPlacement { #[prost(message, optional, tag = "1")] @@ -659,7 +665,6 @@ impl ::prost::Name for LongTermOrderPlacement { /// ConditionalOrderPlacement represents the placement of a conditional order in /// state. It stores the stateful order itself, the `BlockHeight` and /// `TransactionIndex` at which the order was placed and triggered. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConditionalOrderPlacement { #[prost(message, optional, tag = "1")] @@ -685,7 +690,6 @@ impl ::prost::Name for ConditionalOrderPlacement { } /// Order represents a single order belonging to a `Subaccount` /// for a particular `ClobPair`. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Order { /// The unique ID of this order. Meant to be unique across all orders. @@ -763,9 +767,9 @@ pub mod order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Side::Unspecified => "SIDE_UNSPECIFIED", - Side::Buy => "SIDE_BUY", - Side::Sell => "SIDE_SELL", + Self::Unspecified => "SIDE_UNSPECIFIED", + Self::Buy => "SIDE_BUY", + Self::Sell => "SIDE_SELL", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -807,9 +811,8 @@ pub mod order { /// any newly-placed post only orders that would cross with other maker /// orders. PostOnly = 2, - /// TIME_IN_FORCE_FILL_OR_KILL enforces that an order will either be filled - /// completely and immediately by maker orders on the book or canceled if the - /// entire amount can‘t be matched. + /// TIME_IN_FORCE_FILL_OR_KILL has been deprecated and will be removed in + /// future versions. FillOrKill = 3, } impl TimeInForce { @@ -819,10 +822,10 @@ pub mod order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - TimeInForce::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", - TimeInForce::Ioc => "TIME_IN_FORCE_IOC", - TimeInForce::PostOnly => "TIME_IN_FORCE_POST_ONLY", - TimeInForce::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", + Self::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", + Self::Ioc => "TIME_IN_FORCE_IOC", + Self::PostOnly => "TIME_IN_FORCE_POST_ONLY", + Self::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -868,9 +871,9 @@ pub mod order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - ConditionType::Unspecified => "CONDITION_TYPE_UNSPECIFIED", - ConditionType::StopLoss => "CONDITION_TYPE_STOP_LOSS", - ConditionType::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", + Self::Unspecified => "CONDITION_TYPE_UNSPECIFIED", + Self::StopLoss => "CONDITION_TYPE_STOP_LOSS", + Self::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -884,8 +887,7 @@ pub mod order { } } /// Information about when the order expires. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum GoodTilOneof { /// The last block this order can be executed at (after which it will be /// unfillable). Used only for Short-Term orders. If this value is non-zero @@ -916,8 +918,7 @@ impl ::prost::Name for Order { /// transaction was placed. This proto includes both block height and the /// transaction index that the specific transaction was placed. This information /// is used for ordering by time priority when the chain is restarted. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct TransactionOrdering { /// Block height in which the transaction was placed. #[prost(uint32, tag = "1")] @@ -936,10 +937,41 @@ impl ::prost::Name for TransactionOrdering { "/dydxprotocol.clob.TransactionOrdering".into() } } +/// StreamLiquidationOrder represents an protocol-generated IOC liquidation +/// order. Used in full node streaming. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamLiquidationOrder { + /// Information about this liquidation order. + #[prost(message, optional, tag = "1")] + pub liquidation_info: ::core::option::Option, + /// CLOB pair ID of the CLOB pair the liquidation order will be matched + /// against. + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// True if this is a buy order liquidating a short position, false if vice + /// versa. + #[prost(bool, tag = "3")] + pub is_buy: bool, + /// The number of base quantums for this liquidation order. + #[prost(uint64, tag = "4")] + pub quantums: u64, + /// The subticks this liquidation order will be submitted at. + #[prost(uint64, tag = "5")] + pub subticks: u64, +} +impl ::prost::Name for StreamLiquidationOrder { + const NAME: &'static str = "StreamLiquidationOrder"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamLiquidationOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamLiquidationOrder".into() + } +} /// ClobMatch represents an operations queue entry around all different types /// of matches, specifically regular matches, liquidation matches, and /// deleveraging matches. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ClobMatch { /// The match type that this message includes. @@ -949,7 +981,6 @@ pub struct ClobMatch { /// Nested message and enum types in `ClobMatch`. pub mod clob_match { /// The match type that this message includes. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Match { #[prost(message, tag = "1")] @@ -971,7 +1002,6 @@ impl ::prost::Name for ClobMatch { } } /// MakerFill represents the filled amount of a matched maker order. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MakerFill { /// The filled amount of the matched maker order, in base quantums. @@ -993,7 +1023,6 @@ impl ::prost::Name for MakerFill { } } /// MatchOrders is an injected message used for matching orders. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MatchOrders { /// The `OrderId` of the taker order. @@ -1015,7 +1044,6 @@ impl ::prost::Name for MatchOrders { } /// MatchPerpetualLiquidation is an injected message used for liquidating a /// subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MatchPerpetualLiquidation { /// ID of the subaccount that was liquidated. @@ -1049,7 +1077,6 @@ impl ::prost::Name for MatchPerpetualLiquidation { } /// MatchPerpetualDeleveraging is an injected message used for deleveraging a /// subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MatchPerpetualDeleveraging { /// ID of the subaccount that was liquidated. @@ -1071,7 +1098,6 @@ pub struct MatchPerpetualDeleveraging { /// Nested message and enum types in `MatchPerpetualDeleveraging`. pub mod match_perpetual_deleveraging { /// Fill represents a fill between the liquidated and offsetting subaccount. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Fill { /// ID of the subaccount that was used to offset the liquidated subaccount's @@ -1108,7 +1134,6 @@ impl ::prost::Name for MatchPerpetualDeleveraging { } } /// MEVMatch represents all necessary data to calculate MEV for a regular match. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MevMatch { #[prost(message, optional, tag = "1")] @@ -1144,7 +1169,6 @@ impl ::prost::Name for MevMatch { } /// MEVLiquidationMatch represents all necessary data to calculate MEV for a /// liquidation. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MevLiquidationMatch { #[prost(message, optional, tag = "1")] @@ -1179,8 +1203,7 @@ impl ::prost::Name for MevLiquidationMatch { } } /// ClobMidPrice contains the mid price of a CLOB pair, represented by it's ID. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ClobMidPrice { #[prost(message, optional, tag = "1")] pub clob_pair: ::core::option::Option, @@ -1199,7 +1222,6 @@ impl ::prost::Name for ClobMidPrice { } /// ValidatorMevMatches contains all matches from the validator's local /// operations queue. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValidatorMevMatches { #[prost(message, repeated, tag = "1")] @@ -1219,7 +1241,6 @@ impl ::prost::Name for ValidatorMevMatches { } /// MevNodeToNodeMetrics is a data structure for encapsulating all MEV node <> /// node metrics. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MevNodeToNodeMetrics { #[prost(message, optional, tag = "1")] @@ -1242,7 +1263,6 @@ impl ::prost::Name for MevNodeToNodeMetrics { } } /// OrderRemoval is a request type used for forced removal of stateful orders. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderRemoval { #[prost(message, optional, tag = "1")] @@ -1302,6 +1322,9 @@ pub mod order_removal { /// REMOVAL_REASON_FULLY_FILLED represents a removal of an order that /// would lead to the subaccount violating isolated subaccount constraints. ViolatesIsolatedSubaccountConstraints = 8, + /// REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED represents a removal of an order + /// that was placed using an expired permissioned key. + PermissionedKeyExpired = 9, } impl RemovalReason { /// String value of the enum field names used in the ProtoBuf definition. @@ -1310,25 +1333,24 @@ pub mod order_removal { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - RemovalReason::Unspecified => "REMOVAL_REASON_UNSPECIFIED", - RemovalReason::Undercollateralized => { - "REMOVAL_REASON_UNDERCOLLATERALIZED" - } - RemovalReason::InvalidReduceOnly => "REMOVAL_REASON_INVALID_REDUCE_ONLY", - RemovalReason::PostOnlyWouldCrossMakerOrder => { + Self::Unspecified => "REMOVAL_REASON_UNSPECIFIED", + Self::Undercollateralized => "REMOVAL_REASON_UNDERCOLLATERALIZED", + Self::InvalidReduceOnly => "REMOVAL_REASON_INVALID_REDUCE_ONLY", + Self::PostOnlyWouldCrossMakerOrder => { "REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" } - RemovalReason::InvalidSelfTrade => "REMOVAL_REASON_INVALID_SELF_TRADE", - RemovalReason::ConditionalFokCouldNotBeFullyFilled => { + Self::InvalidSelfTrade => "REMOVAL_REASON_INVALID_SELF_TRADE", + Self::ConditionalFokCouldNotBeFullyFilled => { "REMOVAL_REASON_CONDITIONAL_FOK_COULD_NOT_BE_FULLY_FILLED" } - RemovalReason::ConditionalIocWouldRestOnBook => { + Self::ConditionalIocWouldRestOnBook => { "REMOVAL_REASON_CONDITIONAL_IOC_WOULD_REST_ON_BOOK" } - RemovalReason::FullyFilled => "REMOVAL_REASON_FULLY_FILLED", - RemovalReason::ViolatesIsolatedSubaccountConstraints => { + Self::FullyFilled => "REMOVAL_REASON_FULLY_FILLED", + Self::ViolatesIsolatedSubaccountConstraints => { "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" } + Self::PermissionedKeyExpired => "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1351,6 +1373,9 @@ pub mod order_removal { "REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" => { Some(Self::ViolatesIsolatedSubaccountConstraints) } + "REMOVAL_REASON_PERMISSIONED_KEY_EXPIRED" => { + Some(Self::PermissionedKeyExpired) + } _ => None, } } @@ -1367,7 +1392,6 @@ impl ::prost::Name for OrderRemoval { } } /// MsgCreateClobPair is a message used by x/gov for creating a new clob pair. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCreateClobPair { /// The address that controls the module. @@ -1388,8 +1412,7 @@ impl ::prost::Name for MsgCreateClobPair { } } /// MsgCreateClobPairResponse defines the CreateClobPair response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCreateClobPairResponse {} impl ::prost::Name for MsgCreateClobPairResponse { const NAME: &'static str = "MsgCreateClobPairResponse"; @@ -1403,7 +1426,6 @@ impl ::prost::Name for MsgCreateClobPairResponse { } /// MsgProposedOperations is a message injected by block proposers to /// specify the operations that occurred in a block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgProposedOperations { /// The list of operations proposed by the block proposer. @@ -1422,8 +1444,7 @@ impl ::prost::Name for MsgProposedOperations { } /// MsgProposedOperationsResponse is the response type of the message injected /// by block proposers to specify the operations that occurred in a block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgProposedOperationsResponse {} impl ::prost::Name for MsgProposedOperationsResponse { const NAME: &'static str = "MsgProposedOperationsResponse"; @@ -1436,7 +1457,6 @@ impl ::prost::Name for MsgProposedOperationsResponse { } } /// MsgPlaceOrder is a request type used for placing orders. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgPlaceOrder { #[prost(message, optional, tag = "1")] @@ -1453,8 +1473,7 @@ impl ::prost::Name for MsgPlaceOrder { } } /// MsgPlaceOrderResponse is a response type used for placing orders. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgPlaceOrderResponse {} impl ::prost::Name for MsgPlaceOrderResponse { const NAME: &'static str = "MsgPlaceOrderResponse"; @@ -1467,7 +1486,6 @@ impl ::prost::Name for MsgPlaceOrderResponse { } } /// MsgCancelOrder is a request type used for canceling orders. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCancelOrder { #[prost(message, optional, tag = "1")] @@ -1479,8 +1497,7 @@ pub struct MsgCancelOrder { /// Nested message and enum types in `MsgCancelOrder`. pub mod msg_cancel_order { /// Information about when the order cancellation expires. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum GoodTilOneof { /// The last block this order cancellation can be executed at. /// Used only for Short-Term orders and must be zero for stateful orders. @@ -1506,8 +1523,7 @@ impl ::prost::Name for MsgCancelOrder { } } /// MsgCancelOrderResponse is a response type used for canceling orders. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCancelOrderResponse {} impl ::prost::Name for MsgCancelOrderResponse { const NAME: &'static str = "MsgCancelOrderResponse"; @@ -1522,7 +1538,6 @@ impl ::prost::Name for MsgCancelOrderResponse { /// MsgBatchCancel is a request type used for batch canceling orders. /// This msg is not atomic. Cancels will be performed optimistically even /// if some cancels are invalid or fail. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgBatchCancel { /// The subaccount this batch cancel will be applied for. @@ -1548,7 +1563,6 @@ impl ::prost::Name for MsgBatchCancel { /// OrderBatch represents a batch of orders all belonging to a single clob pair /// id. Along with a subaccount id and an order flag, is used to represent a /// batch of orders that share the same subaccount, order flag, and clob pair id. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderBatch { /// The Clob Pair ID all orders in this order batch belong to. @@ -1572,7 +1586,6 @@ impl ::prost::Name for OrderBatch { } /// MsgBatchCancelResponse is a response type used for batch canceling orders. /// It indicates which cancel orders have succeeded or failed. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgBatchCancelResponse { /// A batch of short term cancel orders that have succeeded. @@ -1593,7 +1606,6 @@ impl ::prost::Name for MsgBatchCancelResponse { } } /// MsgUpdateClobPair is a request type used for updating a ClobPair in state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateClobPair { /// Authority is the address that may send this message. @@ -1615,8 +1627,7 @@ impl ::prost::Name for MsgUpdateClobPair { } /// MsgUpdateClobPairResponse is a response type used for setting a ClobPair's /// status. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateClobPairResponse {} impl ::prost::Name for MsgUpdateClobPairResponse { const NAME: &'static str = "MsgUpdateClobPairResponse"; @@ -1630,7 +1641,6 @@ impl ::prost::Name for MsgUpdateClobPairResponse { } /// OperationRaw represents an operation in the proposed operations. /// Note that the `order_placement` operation is a signed message. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OperationRaw { /// operationRaw represents an operation that occurred, which can be a match, @@ -1642,7 +1652,6 @@ pub struct OperationRaw { pub mod operation_raw { /// operationRaw represents an operation that occurred, which can be a match, /// a signed order placement, or an order removal. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Operation { #[prost(message, tag = "1")] @@ -1665,7 +1674,6 @@ impl ::prost::Name for OperationRaw { } /// MsgUpdateEquityTierLimitConfiguration is the Msg/EquityTierLimitConfiguration /// request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateEquityTierLimitConfiguration { #[prost(string, tag = "1")] @@ -1687,8 +1695,7 @@ impl ::prost::Name for MsgUpdateEquityTierLimitConfiguration { } /// MsgUpdateEquityTierLimitConfiguration is the Msg/EquityTierLimitConfiguration /// response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateEquityTierLimitConfigurationResponse {} impl ::prost::Name for MsgUpdateEquityTierLimitConfigurationResponse { const NAME: &'static str = "MsgUpdateEquityTierLimitConfigurationResponse"; @@ -1702,7 +1709,6 @@ impl ::prost::Name for MsgUpdateEquityTierLimitConfigurationResponse { } /// MsgUpdateBlockRateLimitConfiguration is the Msg/BlockRateLimitConfiguration /// request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateBlockRateLimitConfiguration { #[prost(string, tag = "1")] @@ -1724,8 +1730,7 @@ impl ::prost::Name for MsgUpdateBlockRateLimitConfiguration { } /// MsgUpdateBlockRateLimitConfiguration is a response type for updating the /// liquidations config. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateBlockRateLimitConfigurationResponse {} impl ::prost::Name for MsgUpdateBlockRateLimitConfigurationResponse { const NAME: &'static str = "MsgUpdateBlockRateLimitConfigurationResponse"; @@ -1739,7 +1744,6 @@ impl ::prost::Name for MsgUpdateBlockRateLimitConfigurationResponse { } /// MsgUpdateLiquidationsConfig is a request type for updating the liquidations /// config. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateLiquidationsConfig { /// Authority is the address that may send this message. @@ -1761,8 +1765,7 @@ impl ::prost::Name for MsgUpdateLiquidationsConfig { } } /// MsgUpdateLiquidationsConfig is the Msg/LiquidationsConfig response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateLiquidationsConfigResponse {} impl ::prost::Name for MsgUpdateLiquidationsConfigResponse { const NAME: &'static str = "MsgUpdateLiquidationsConfigResponse"; @@ -1776,7 +1779,13 @@ impl ::prost::Name for MsgUpdateLiquidationsConfigResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -1784,6 +1793,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -1799,8 +1809,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -1825,7 +1835,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -1873,8 +1883,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1899,8 +1908,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1925,8 +1933,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1951,8 +1958,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1977,8 +1983,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2006,8 +2011,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2035,8 +2039,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2067,8 +2070,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2098,8 +2100,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2118,7 +2119,6 @@ pub mod msg_client { } /// Operation represents an operation in the proposed operations. Operation is /// used internally within the memclob only. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Operation { /// operation represents the operation that occurred, which can be a match, @@ -2132,7 +2132,6 @@ pub mod operation { /// operation represents the operation that occurred, which can be a match, /// short term order placement, short term order cancellation, or the placement /// of a pre-existing stateful order. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Operation { #[prost(message, tag = "1")] @@ -2157,7 +2156,6 @@ impl ::prost::Name for Operation { } /// InternalOperation represents an internal operation in the operations to /// propose. InternalOperation is used internally within the memclob only. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct InternalOperation { /// operation represents the operation that occurred, which can be a match, @@ -2171,7 +2169,6 @@ pub mod internal_operation { /// operation represents the operation that occurred, which can be a match, /// Short-Term order placement, or the placement of a pre-existing stateful /// order. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Operation { #[prost(message, tag = "1")] @@ -2205,21 +2202,23 @@ impl ::prost::Name for InternalOperation { /// - Conditional order IDs triggered in the last block. /// - Conditional order IDs placed, but not triggered in the last block. /// - The height of the block in which the events occurred. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProcessProposerMatchesEvents { + #[deprecated] #[prost(message, repeated, tag = "1")] pub placed_long_term_order_ids: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "2")] pub expired_stateful_order_ids: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "3")] pub order_ids_filled_in_last_block: ::prost::alloc::vec::Vec, + #[deprecated] #[prost(message, repeated, tag = "4")] pub placed_stateful_cancellation_order_ids: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "5")] pub removed_stateful_order_ids: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "6")] pub conditional_order_ids_triggered_in_last_block: ::prost::alloc::vec::Vec, + #[deprecated] #[prost(message, repeated, tag = "7")] pub placed_conditional_order_ids: ::prost::alloc::vec::Vec, #[prost(uint32, tag = "8")] @@ -2236,8 +2235,7 @@ impl ::prost::Name for ProcessProposerMatchesEvents { } } /// QueryGetClobPairRequest is request type for the ClobPair method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryGetClobPairRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -2253,8 +2251,7 @@ impl ::prost::Name for QueryGetClobPairRequest { } } /// QueryClobPairResponse is response type for the ClobPair method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryClobPairResponse { #[prost(message, optional, tag = "1")] pub clob_pair: ::core::option::Option, @@ -2270,7 +2267,6 @@ impl ::prost::Name for QueryClobPairResponse { } } /// QueryAllClobPairRequest is request type for the ClobPairAll method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllClobPairRequest { #[prost(message, optional, tag = "1")] @@ -2289,7 +2285,6 @@ impl ::prost::Name for QueryAllClobPairRequest { } } /// QueryClobPairAllResponse is response type for the ClobPairAll method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryClobPairAllResponse { #[prost(message, repeated, tag = "1")] @@ -2311,7 +2306,6 @@ impl ::prost::Name for QueryClobPairAllResponse { } /// MevNodeToNodeCalculationRequest is a request message used to run the /// MEV node <> node calculation. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MevNodeToNodeCalculationRequest { /// Represents the matches on the "block proposer". Note that this field @@ -2336,7 +2330,6 @@ impl ::prost::Name for MevNodeToNodeCalculationRequest { } /// MevNodeToNodeCalculationResponse is a response message that contains the /// MEV node <> node calculation result. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MevNodeToNodeCalculationResponse { #[prost(message, repeated, tag = "1")] @@ -2347,8 +2340,7 @@ pub struct MevNodeToNodeCalculationResponse { /// Nested message and enum types in `MevNodeToNodeCalculationResponse`. pub mod mev_node_to_node_calculation_response { /// MevAndVolumePerClob contains information about the MEV and volume per CLOB. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MevAndVolumePerClob { #[prost(uint32, tag = "1")] pub clob_pair_id: u32, @@ -2382,8 +2374,7 @@ impl ::prost::Name for MevNodeToNodeCalculationResponse { } /// QueryEquityTierLimitConfigurationRequest is a request message for /// EquityTierLimitConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryEquityTierLimitConfigurationRequest {} impl ::prost::Name for QueryEquityTierLimitConfigurationRequest { const NAME: &'static str = "QueryEquityTierLimitConfigurationRequest"; @@ -2397,7 +2388,6 @@ impl ::prost::Name for QueryEquityTierLimitConfigurationRequest { } /// QueryEquityTierLimitConfigurationResponse is a response message that contains /// the EquityTierLimitConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryEquityTierLimitConfigurationResponse { #[prost(message, optional, tag = "1")] @@ -2415,8 +2405,7 @@ impl ::prost::Name for QueryEquityTierLimitConfigurationResponse { } /// QueryBlockRateLimitConfigurationRequest is a request message for /// BlockRateLimitConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryBlockRateLimitConfigurationRequest {} impl ::prost::Name for QueryBlockRateLimitConfigurationRequest { const NAME: &'static str = "QueryBlockRateLimitConfigurationRequest"; @@ -2430,7 +2419,6 @@ impl ::prost::Name for QueryBlockRateLimitConfigurationRequest { } /// QueryBlockRateLimitConfigurationResponse is a response message that contains /// the BlockRateLimitConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryBlockRateLimitConfigurationResponse { #[prost(message, optional, tag = "1")] @@ -2447,7 +2435,6 @@ impl ::prost::Name for QueryBlockRateLimitConfigurationResponse { } } /// QueryStatefulOrderRequest is a request message for StatefulOrder. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryStatefulOrderRequest { /// Order id to query. @@ -2466,7 +2453,6 @@ impl ::prost::Name for QueryStatefulOrderRequest { } /// QueryStatefulOrderResponse is a response message that contains the stateful /// order. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryStatefulOrderResponse { /// Stateful order placement. @@ -2491,8 +2477,7 @@ impl ::prost::Name for QueryStatefulOrderResponse { } /// QueryLiquidationsConfigurationRequest is a request message for /// LiquidationsConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryLiquidationsConfigurationRequest {} impl ::prost::Name for QueryLiquidationsConfigurationRequest { const NAME: &'static str = "QueryLiquidationsConfigurationRequest"; @@ -2506,8 +2491,7 @@ impl ::prost::Name for QueryLiquidationsConfigurationRequest { } /// QueryLiquidationsConfigurationResponse is a response message that contains /// the LiquidationsConfiguration. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryLiquidationsConfigurationResponse { #[prost(message, optional, tag = "1")] pub liquidations_config: ::core::option::Option, @@ -2524,12 +2508,14 @@ impl ::prost::Name for QueryLiquidationsConfigurationResponse { } /// StreamOrderbookUpdatesRequest is a request message for the /// StreamOrderbookUpdates method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StreamOrderbookUpdatesRequest { /// Clob pair ids to stream orderbook updates for. #[prost(uint32, repeated, tag = "1")] pub clob_pair_id: ::prost::alloc::vec::Vec, + /// Subaccount ids to stream subaccount updates for. + #[prost(message, repeated, tag = "2")] + pub subaccount_ids: ::prost::alloc::vec::Vec, } impl ::prost::Name for StreamOrderbookUpdatesRequest { const NAME: &'static str = "StreamOrderbookUpdatesRequest"; @@ -2543,19 +2529,11 @@ impl ::prost::Name for StreamOrderbookUpdatesRequest { } /// StreamOrderbookUpdatesResponse is a response message for the /// StreamOrderbookUpdates method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StreamOrderbookUpdatesResponse { - /// Orderbook updates for the clob pair. + /// Batch of updates for the clob pair. #[prost(message, repeated, tag = "1")] pub updates: ::prost::alloc::vec::Vec, - /// ---Additional fields used to debug issues--- - /// Block height of the updates. - #[prost(uint32, tag = "2")] - pub block_height: u32, - /// Exec mode of the updates. - #[prost(uint32, tag = "3")] - pub exec_mode: u32, } impl ::prost::Name for StreamOrderbookUpdatesResponse { const NAME: &'static str = "StreamOrderbookUpdatesResponse"; @@ -2569,25 +2547,33 @@ impl ::prost::Name for StreamOrderbookUpdatesResponse { } /// StreamUpdate is an update that will be pushed through the /// GRPC stream. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StreamUpdate { + /// Block height of the update. + #[prost(uint32, tag = "1")] + pub block_height: u32, + /// Exec mode of the update. + #[prost(uint32, tag = "2")] + pub exec_mode: u32, /// Contains one of an StreamOrderbookUpdate, - /// StreamOrderbookFill. - #[prost(oneof = "stream_update::UpdateMessage", tags = "1, 2")] + /// StreamOrderbookFill, StreamTakerOrderStatus. + #[prost(oneof = "stream_update::UpdateMessage", tags = "3, 4, 5, 6")] pub update_message: ::core::option::Option, } /// Nested message and enum types in `StreamUpdate`. pub mod stream_update { /// Contains one of an StreamOrderbookUpdate, - /// StreamOrderbookFill. - #[allow(clippy::derive_partial_eq_without_eq)] + /// StreamOrderbookFill, StreamTakerOrderStatus. #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum UpdateMessage { - #[prost(message, tag = "1")] + #[prost(message, tag = "3")] OrderbookUpdate(super::StreamOrderbookUpdate), - #[prost(message, tag = "2")] + #[prost(message, tag = "4")] OrderFill(super::StreamOrderbookFill), + #[prost(message, tag = "5")] + TakerOrder(super::StreamTakerOrder), + #[prost(message, tag = "6")] + SubaccountUpdate(super::super::subaccounts::StreamSubaccountUpdate), } } impl ::prost::Name for StreamUpdate { @@ -2602,21 +2588,20 @@ impl ::prost::Name for StreamUpdate { } /// StreamOrderbookUpdate provides information on an orderbook update. Used in /// the full node GRPC stream. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StreamOrderbookUpdate { + /// Snapshot indicates if the response is from a snapshot of the orderbook. + /// All updates should be ignored until snapshot is recieved. + /// If the snapshot is true, then all previous entries should be + /// discarded and the orderbook should be resynced. + #[prost(bool, tag = "1")] + pub snapshot: bool, /// Orderbook updates for the clob pair. Can contain order place, removals, /// or updates. - #[prost(message, repeated, tag = "1")] + #[prost(message, repeated, tag = "2")] pub updates: ::prost::alloc::vec::Vec< super::indexer::off_chain_updates::OffChainUpdateV1, >, - /// Snapshot indicates if the response is from a snapshot of the orderbook. - /// This is true for the initial response and false for all subsequent updates. - /// Note that if the snapshot is true, then all previous entries should be - /// discarded and the orderbook should be resynced. - #[prost(bool, tag = "2")] - pub snapshot: bool, } impl ::prost::Name for StreamOrderbookUpdate { const NAME: &'static str = "StreamOrderbookUpdate"; @@ -2630,11 +2615,10 @@ impl ::prost::Name for StreamOrderbookUpdate { } /// StreamOrderbookFill provides information on an orderbook fill. Used in /// the full node GRPC stream. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StreamOrderbookFill { /// Clob match. Provides information on which orders were matched - /// and the type of order. Fill amounts here are relative. + /// and the type of order. #[prost(message, optional, tag = "1")] pub clob_match: ::core::option::Option, /// All orders involved in the specified clob match. Used to look up @@ -2642,7 +2626,7 @@ pub struct StreamOrderbookFill { #[prost(message, repeated, tag = "2")] pub orders: ::prost::alloc::vec::Vec, /// Resulting fill amounts for each order in the orders array. - #[prost(uint64, repeated, packed = "false", tag = "3")] + #[prost(uint64, repeated, tag = "3")] pub fill_amounts: ::prost::alloc::vec::Vec, } impl ::prost::Name for StreamOrderbookFill { @@ -2655,9 +2639,82 @@ impl ::prost::Name for StreamOrderbookFill { "/dydxprotocol.clob.StreamOrderbookFill".into() } } +/// StreamTakerOrder provides information on a taker order that was attempted +/// to be matched on the orderbook. +/// It is intended to be used only in full node streaming. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamTakerOrder { + /// Information on the taker order after it is matched on the book, + /// either successfully or unsuccessfully. + #[prost(message, optional, tag = "3")] + pub taker_order_status: ::core::option::Option, + /// The taker order that was matched on the orderbook. Can be a + /// regular order or a liquidation order. + #[prost(oneof = "stream_taker_order::TakerOrder", tags = "1, 2")] + pub taker_order: ::core::option::Option, +} +/// Nested message and enum types in `StreamTakerOrder`. +pub mod stream_taker_order { + /// The taker order that was matched on the orderbook. Can be a + /// regular order or a liquidation order. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum TakerOrder { + #[prost(message, tag = "1")] + Order(super::Order), + #[prost(message, tag = "2")] + LiquidationOrder(super::StreamLiquidationOrder), + } +} +impl ::prost::Name for StreamTakerOrder { + const NAME: &'static str = "StreamTakerOrder"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamTakerOrder".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamTakerOrder".into() + } +} +/// StreamTakerOrderStatus is a representation of a taker order +/// after it is attempted to be matched on the orderbook. +/// It is intended to be used only in full node streaming. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct StreamTakerOrderStatus { + /// The state of the taker order after attempting to match it against the + /// orderbook. Possible enum values can be found here: + /// + #[prost(uint32, tag = "1")] + pub order_status: u32, + /// The amount of remaining (non-matched) base quantums of this taker order. + #[prost(uint64, tag = "2")] + pub remaining_quantums: u64, + /// The amount of base quantums that were *optimistically* filled for this + /// taker order when the order is matched against the orderbook. Note that if + /// any quantums of this order were optimistically filled or filled in state + /// before this invocation of the matching loop, this value will not include + /// them. + #[prost(uint64, tag = "3")] + pub optimistically_filled_quantums: u64, +} +impl ::prost::Name for StreamTakerOrderStatus { + const NAME: &'static str = "StreamTakerOrderStatus"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StreamTakerOrderStatus".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StreamTakerOrderStatus".into() + } +} /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -2665,6 +2722,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -2680,8 +2738,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -2706,7 +2764,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -2753,8 +2811,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2779,8 +2836,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2805,8 +2861,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2838,8 +2893,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2871,8 +2925,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2904,8 +2957,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2935,8 +2987,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2964,8 +3015,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -2982,3 +3032,33 @@ pub mod query_client { } } } +/// StagedFinalizeBlockEvent is an event staged during `FinalizeBlock`. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StagedFinalizeBlockEvent { + /// Contains one of StreamOrderbookFill, StreamSubaccountUpdate. + #[prost(oneof = "staged_finalize_block_event::Event", tags = "1, 2, 3")] + pub event: ::core::option::Option, +} +/// Nested message and enum types in `StagedFinalizeBlockEvent`. +pub mod staged_finalize_block_event { + /// Contains one of StreamOrderbookFill, StreamSubaccountUpdate. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Event { + #[prost(message, tag = "1")] + OrderFill(super::StreamOrderbookFill), + #[prost(message, tag = "2")] + SubaccountUpdate(super::super::subaccounts::StreamSubaccountUpdate), + #[prost(message, tag = "3")] + OrderbookUpdate(super::StreamOrderbookUpdate), + } +} +impl ::prost::Name for StagedFinalizeBlockEvent { + const NAME: &'static str = "StagedFinalizeBlockEvent"; + const PACKAGE: &'static str = "dydxprotocol.clob"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.clob.StagedFinalizeBlockEvent".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.clob.StagedFinalizeBlockEvent".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs b/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs index ae7eb45729..fccaa51697 100644 --- a/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs +++ b/v4-proto-rs/src/dydxprotocol.daemons.bridge.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// AddBridgeEventsRequest is a request message that contains a list of new /// bridge events. The events should be contiguous and sorted by (unique) id. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AddBridgeEventsRequest { #[prost(message, repeated, tag = "1")] @@ -18,8 +17,7 @@ impl ::prost::Name for AddBridgeEventsRequest { } } /// AddBridgeEventsResponse is a response message for BridgeEventRequest. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct AddBridgeEventsResponse {} impl ::prost::Name for AddBridgeEventsResponse { const NAME: &'static str = "AddBridgeEventsResponse"; @@ -33,7 +31,13 @@ impl ::prost::Name for AddBridgeEventsResponse { } /// Generated client implementations. pub mod bridge_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// BridgeService defines the gRPC service used by bridge daemon. @@ -41,6 +45,7 @@ pub mod bridge_service_client { pub struct BridgeServiceClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl BridgeServiceClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -56,8 +61,8 @@ pub mod bridge_service_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -82,7 +87,7 @@ pub mod bridge_service_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { BridgeServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -129,8 +134,7 @@ pub mod bridge_service_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs b/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs index b87a3eed41..b51725814b 100644 --- a/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs +++ b/v4-proto-rs/src/dydxprotocol.daemons.liquidation.rs @@ -3,7 +3,6 @@ /// subaccount ids that potentially need to be liquidated. The list of subaccount /// ids should not contain duplicates. The application should re-verify these /// subaccount ids against current state before liquidating their positions. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LiquidateSubaccountsRequest { /// The block height at which the liquidation daemon is processing. @@ -37,8 +36,7 @@ impl ::prost::Name for LiquidateSubaccountsRequest { } /// LiquidateSubaccountsResponse is a response message for /// LiquidateSubaccountsRequest. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct LiquidateSubaccountsResponse {} impl ::prost::Name for LiquidateSubaccountsResponse { const NAME: &'static str = "LiquidateSubaccountsResponse"; @@ -52,7 +50,13 @@ impl ::prost::Name for LiquidateSubaccountsResponse { } /// Generated client implementations. pub mod liquidation_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// LiquidationService defines the gRPC service used by liquidation daemon. @@ -60,6 +64,7 @@ pub mod liquidation_service_client { pub struct LiquidationServiceClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl LiquidationServiceClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -75,8 +80,8 @@ pub mod liquidation_service_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -101,7 +106,7 @@ pub mod liquidation_service_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { LiquidationServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -148,8 +153,7 @@ pub mod liquidation_service_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs b/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs index bb273d7232..c8f9553adf 100644 --- a/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs +++ b/v4-proto-rs/src/dydxprotocol.daemons.pricefeed.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// UpdateMarketPriceRequest is a request message updating market prices. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateMarketPricesRequest { #[prost(message, repeated, tag = "1")] @@ -17,8 +16,7 @@ impl ::prost::Name for UpdateMarketPricesRequest { } } /// UpdateMarketPricesResponse is a response message for updating market prices. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct UpdateMarketPricesResponse {} impl ::prost::Name for UpdateMarketPricesResponse { const NAME: &'static str = "UpdateMarketPricesResponse"; @@ -31,7 +29,6 @@ impl ::prost::Name for UpdateMarketPricesResponse { } } /// ExchangePrice represents a specific exchange's market price -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExchangePrice { #[prost(string, tag = "1")] @@ -52,7 +49,6 @@ impl ::prost::Name for ExchangePrice { } } /// MarketPriceUpdate represents an update to a single market -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketPriceUpdate { #[prost(uint32, tag = "1")] @@ -72,7 +68,13 @@ impl ::prost::Name for MarketPriceUpdate { } /// Generated client implementations. pub mod price_feed_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// PriceFeedService provides methods related to market prices. @@ -80,6 +82,7 @@ pub mod price_feed_service_client { pub struct PriceFeedServiceClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl PriceFeedServiceClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -95,8 +98,8 @@ pub mod price_feed_service_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -121,7 +124,7 @@ pub mod price_feed_service_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { PriceFeedServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -168,8 +171,7 @@ pub mod price_feed_service_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.delaymsg.rs b/v4-proto-rs/src/dydxprotocol.delaymsg.rs index b4e043a63f..ee9ac13c75 100644 --- a/v4-proto-rs/src/dydxprotocol.delaymsg.rs +++ b/v4-proto-rs/src/dydxprotocol.delaymsg.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// BlockMessageIds stores the id of each message that should be processed at a /// given block height. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockMessageIds { /// ids stores a list of DelayedMessage ids that should be processed at a given @@ -20,7 +19,6 @@ impl ::prost::Name for BlockMessageIds { } } /// DelayedMessage is a message that is delayed until a certain block height. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DelayedMessage { /// The ID of the delayed message. @@ -44,7 +42,6 @@ impl ::prost::Name for DelayedMessage { } } /// GenesisState defines the delaymsg module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// delayed_messages is a list of delayed messages. @@ -66,8 +63,7 @@ impl ::prost::Name for GenesisState { } /// QueryNextDelayedMessageIdRequest is the request type for the /// NextDelayedMessageId RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryNextDelayedMessageIdRequest {} impl ::prost::Name for QueryNextDelayedMessageIdRequest { const NAME: &'static str = "QueryNextDelayedMessageIdRequest"; @@ -81,8 +77,7 @@ impl ::prost::Name for QueryNextDelayedMessageIdRequest { } /// QueryNextDelayedMessageIdResponse is the response type for the /// NextDelayedMessageId RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryNextDelayedMessageIdResponse { #[prost(uint32, tag = "1")] pub next_delayed_message_id: u32, @@ -98,8 +93,7 @@ impl ::prost::Name for QueryNextDelayedMessageIdResponse { } } /// QueryMessageRequest is the request type for the Message RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryMessageRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -115,7 +109,6 @@ impl ::prost::Name for QueryMessageRequest { } } /// QueryGetMessageResponse is the response type for the Message RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryMessageResponse { #[prost(message, optional, tag = "1")] @@ -133,8 +126,7 @@ impl ::prost::Name for QueryMessageResponse { } /// QueryBlockMessageIdsRequest is the request type for the BlockMessageIds /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryBlockMessageIdsRequest { #[prost(uint32, tag = "1")] pub block_height: u32, @@ -151,7 +143,6 @@ impl ::prost::Name for QueryBlockMessageIdsRequest { } /// QueryGetBlockMessageIdsResponse is the response type for the BlockMessageIds /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryBlockMessageIdsResponse { #[prost(uint32, repeated, tag = "1")] @@ -169,7 +160,13 @@ impl ::prost::Name for QueryBlockMessageIdsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -177,6 +174,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -192,8 +190,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -218,7 +216,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -265,8 +263,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -296,8 +293,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -322,8 +318,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -341,7 +336,6 @@ pub mod query_client { } } /// MsgDelayMessage is a request type for the DelayMessage method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgDelayMessage { #[prost(string, tag = "1")] @@ -364,8 +358,7 @@ impl ::prost::Name for MsgDelayMessage { } } /// MsgDelayMessageResponse is a response type for the DelayMessage method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgDelayMessageResponse { /// The id of the created delayed message. #[prost(uint64, tag = "1")] @@ -383,7 +376,13 @@ impl ::prost::Name for MsgDelayMessageResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -391,6 +390,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -406,8 +406,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -432,7 +432,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -480,8 +480,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.epochs.rs b/v4-proto-rs/src/dydxprotocol.epochs.rs index b586a436c1..c1205ef717 100644 --- a/v4-proto-rs/src/dydxprotocol.epochs.rs +++ b/v4-proto-rs/src/dydxprotocol.epochs.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// EpochInfo stores metadata of an epoch timer. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EpochInfo { /// name is the unique identifier. @@ -51,7 +50,6 @@ impl ::prost::Name for EpochInfo { } } /// GenesisState defines the epochs module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// this line is used by starport scaffolding # genesis/proto/state @@ -69,7 +67,6 @@ impl ::prost::Name for GenesisState { } } /// QueryGetEpochInfoRequest is request type for the GetEpochInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryGetEpochInfoRequest { #[prost(string, tag = "1")] @@ -86,7 +83,6 @@ impl ::prost::Name for QueryGetEpochInfoRequest { } } /// QueryEpochInfoResponse is response type for the GetEpochInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryEpochInfoResponse { #[prost(message, optional, tag = "1")] @@ -103,7 +99,6 @@ impl ::prost::Name for QueryEpochInfoResponse { } } /// QueryAllEpochInfoRequest is request type for the AllEpochInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllEpochInfoRequest { #[prost(message, optional, tag = "1")] @@ -122,7 +117,6 @@ impl ::prost::Name for QueryAllEpochInfoRequest { } } /// QueryEpochInfoAllResponse is response type for the AllEpochInfo RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryEpochInfoAllResponse { #[prost(message, repeated, tag = "1")] @@ -144,7 +138,13 @@ impl ::prost::Name for QueryEpochInfoAllResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -152,6 +152,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -167,8 +168,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -193,7 +194,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -240,8 +241,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -266,8 +266,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.feetiers.rs b/v4-proto-rs/src/dydxprotocol.feetiers.rs index 36aa2256ae..1fd082bb1e 100644 --- a/v4-proto-rs/src/dydxprotocol.feetiers.rs +++ b/v4-proto-rs/src/dydxprotocol.feetiers.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// PerpetualFeeParams defines the parameters for perpetual fees. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualFeeParams { /// Sorted fee tiers (lowest requirements first). @@ -18,7 +17,6 @@ impl ::prost::Name for PerpetualFeeParams { } } /// A fee tier for perpetuals -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualFeeTier { /// Human-readable name of the tier, e.g. "Gold". @@ -51,7 +49,6 @@ impl ::prost::Name for PerpetualFeeTier { } } /// GenesisState defines the feetiers module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// The parameters for perpetual fees. @@ -70,8 +67,7 @@ impl ::prost::Name for GenesisState { } /// QueryPerpetualFeeParamsRequest is a request type for the PerpetualFeeParams /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPerpetualFeeParamsRequest {} impl ::prost::Name for QueryPerpetualFeeParamsRequest { const NAME: &'static str = "QueryPerpetualFeeParamsRequest"; @@ -85,7 +81,6 @@ impl ::prost::Name for QueryPerpetualFeeParamsRequest { } /// QueryPerpetualFeeParamsResponse is a response type for the PerpetualFeeParams /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryPerpetualFeeParamsResponse { #[prost(message, optional, tag = "1")] @@ -102,7 +97,6 @@ impl ::prost::Name for QueryPerpetualFeeParamsResponse { } } /// QueryUserFeeTierRequest is a request type for the UserFeeTier RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryUserFeeTierRequest { #[prost(string, tag = "1")] @@ -119,7 +113,6 @@ impl ::prost::Name for QueryUserFeeTierRequest { } } /// QueryUserFeeTierResponse is a request type for the UserFeeTier RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryUserFeeTierResponse { /// Index of the fee tier in the list queried from PerpetualFeeParams. @@ -140,7 +133,13 @@ impl ::prost::Name for QueryUserFeeTierResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -148,6 +147,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -163,8 +163,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -189,7 +189,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -236,8 +236,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -264,8 +263,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -281,7 +279,6 @@ pub mod query_client { } } /// MsgUpdatePerpetualFeeParams is the Msg/UpdatePerpetualFeeParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdatePerpetualFeeParams { #[prost(string, tag = "1")] @@ -302,8 +299,7 @@ impl ::prost::Name for MsgUpdatePerpetualFeeParams { } /// MsgUpdatePerpetualFeeParamsResponse is the Msg/UpdatePerpetualFeeParams /// response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdatePerpetualFeeParamsResponse {} impl ::prost::Name for MsgUpdatePerpetualFeeParamsResponse { const NAME: &'static str = "MsgUpdatePerpetualFeeParamsResponse"; @@ -317,7 +313,13 @@ impl ::prost::Name for MsgUpdatePerpetualFeeParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -325,6 +327,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -340,8 +343,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -366,7 +369,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -413,8 +416,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.govplus.rs b/v4-proto-rs/src/dydxprotocol.govplus.rs index 3d9b4e7aed..2c1b3b58a9 100644 --- a/v4-proto-rs/src/dydxprotocol.govplus.rs +++ b/v4-proto-rs/src/dydxprotocol.govplus.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// GenesisState defines the govplus module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GenesisState {} impl ::prost::Name for GenesisState { const NAME: &'static str = "GenesisState"; @@ -15,7 +14,13 @@ impl ::prost::Name for GenesisState { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -23,6 +28,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -38,8 +44,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -64,7 +70,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -102,7 +108,6 @@ pub mod query_client { } } /// MsgSlashValidator is the Msg/SlashValidator request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSlashValidator { #[prost(string, tag = "1")] @@ -145,8 +150,7 @@ impl ::prost::Name for MsgSlashValidator { } } /// MsgSlashValidatorResponse is the Msg/SlashValidator response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgSlashValidatorResponse {} impl ::prost::Name for MsgSlashValidatorResponse { const NAME: &'static str = "MsgSlashValidatorResponse"; @@ -160,7 +164,13 @@ impl ::prost::Name for MsgSlashValidatorResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -168,6 +178,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -183,8 +194,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -209,7 +220,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -257,8 +268,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.indexer.events.rs b/v4-proto-rs/src/dydxprotocol.indexer.events.rs index a613801c76..84c643dcc6 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.events.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.events.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// FundingUpdate is used for funding update events and includes a funding /// value and an optional funding index that correspond to a perpetual market. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FundingUpdateV1 { /// The id of the perpetual market. @@ -35,7 +34,6 @@ impl ::prost::Name for FundingUpdateV1 { /// 3. Funding rate and index: final funding rate combining all premium samples /// during a `funding-tick` epoch and funding index accordingly updated with /// `funding rate * price`. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FundingEventV1 { /// updates is a list of per-market funding updates for all existing perpetual @@ -81,10 +79,10 @@ pub mod funding_event_v1 { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Type::Unspecified => "TYPE_UNSPECIFIED", - Type::PremiumSample => "TYPE_PREMIUM_SAMPLE", - Type::FundingRateAndIndex => "TYPE_FUNDING_RATE_AND_INDEX", - Type::PremiumVote => "TYPE_PREMIUM_VOTE", + Self::Unspecified => "TYPE_UNSPECIFIED", + Self::PremiumSample => "TYPE_PREMIUM_SAMPLE", + Self::FundingRateAndIndex => "TYPE_FUNDING_RATE_AND_INDEX", + Self::PremiumVote => "TYPE_PREMIUM_VOTE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -111,7 +109,6 @@ impl ::prost::Name for FundingEventV1 { } /// MarketEvent message contains all the information about a market event on /// the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketEventV1 { /// market id. @@ -124,7 +121,6 @@ pub struct MarketEventV1 { /// Nested message and enum types in `MarketEventV1`. pub mod market_event_v1 { /// either an event for price update, market creation, or market modification. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Event { #[prost(message, tag = "2")] @@ -147,8 +143,7 @@ impl ::prost::Name for MarketEventV1 { } /// MarketPriceUpdateEvent message contains all the information about a price /// update on the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MarketPriceUpdateEventV1 { /// price_with_exponent. Multiply by 10 ^ Exponent to get the human readable /// price in dollars. For example if `Exponent == -5` then a `exponent_price` @@ -167,7 +162,6 @@ impl ::prost::Name for MarketPriceUpdateEventV1 { } } /// shared fields between MarketCreateEvent and MarketModifyEvent -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketBaseEventV1 { /// String representation of the market pair, e.g. `BTC-USD` @@ -190,7 +184,6 @@ impl ::prost::Name for MarketBaseEventV1 { } /// MarketCreateEvent message contains all the information about a new market on /// the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketCreateEventV1 { #[prost(message, optional, tag = "1")] @@ -214,7 +207,6 @@ impl ::prost::Name for MarketCreateEventV1 { } /// MarketModifyEvent message contains all the information about a market update /// on the dYdX chain -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketModifyEventV1 { #[prost(message, optional, tag = "1")] @@ -231,7 +223,6 @@ impl ::prost::Name for MarketModifyEventV1 { } } /// SourceOfFunds is the source of funds in a transfer event. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SourceOfFunds { /// one of below @@ -245,7 +236,6 @@ pub mod source_of_funds { /// one of below /// - a subaccount ID /// - a wallet address - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Source { #[prost(message, tag = "1")] @@ -268,7 +258,6 @@ impl ::prost::Name for SourceOfFunds { /// deposit-to-subaccount, or withdraw-from-subaccount on the dYdX chain. /// When a subaccount is involved, a SubaccountUpdateEvent message will /// be produced with the updated asset positions. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransferEventV1 { #[prost(message, optional, tag = "1")] @@ -309,7 +298,6 @@ impl ::prost::Name for TransferEventV1 { /// OrderFillEvent message contains all the information from an order match in /// the dYdX chain. This includes the maker/taker orders that matched and the /// amount filled. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderFillEventV1 { #[prost(message, optional, tag = "1")] @@ -330,6 +318,9 @@ pub struct OrderFillEventV1 { /// Total filled of the taker order in base quantums. #[prost(uint64, tag = "8")] pub total_filled_taker: u64, + /// rev share for affiliates in USDC quantums. + #[prost(uint64, tag = "9")] + pub affiliate_rev_share: u64, /// The type of order fill this event represents. #[prost(oneof = "order_fill_event_v1::TakerOrder", tags = "2, 4")] pub taker_order: ::core::option::Option, @@ -337,7 +328,6 @@ pub struct OrderFillEventV1 { /// Nested message and enum types in `OrderFillEventV1`. pub mod order_fill_event_v1 { /// The type of order fill this event represents. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum TakerOrder { #[prost(message, tag = "2")] @@ -359,7 +349,6 @@ impl ::prost::Name for OrderFillEventV1 { /// DeleveragingEvent message contains all the information for a deleveraging /// on the dYdX chain. This includes the liquidated/offsetting subaccounts and /// the amount filled. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DeleveragingEventV1 { /// ID of the subaccount that was liquidated. @@ -400,7 +389,6 @@ impl ::prost::Name for DeleveragingEventV1 { } /// LiquidationOrder represents the liquidation taker order to be included in a /// liquidation order fill event. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LiquidationOrderV1 { /// ID of the subaccount that was liquidated. @@ -443,7 +431,6 @@ impl ::prost::Name for LiquidationOrderV1 { /// Note: This event message will contain all the updates to a subaccount /// at the end of a block which is why multiple asset/perpetual position /// updates may exist. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SubaccountUpdateEventV1 { #[prost(message, optional, tag = "1")] @@ -473,7 +460,6 @@ impl ::prost::Name for SubaccountUpdateEventV1 { /// order. Currently, this is either the placement of a long-term order, the /// placement or triggering of a conditional order, or the removal of a /// stateful order. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StatefulOrderEventV1 { /// The type of event that this StatefulOrderEvent contains. @@ -484,7 +470,6 @@ pub struct StatefulOrderEventV1 { pub mod stateful_order_event_v1 { /// A stateful order placement contains an order. /// Deprecated in favor of LongTermOrderPlacementV1. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StatefulOrderPlacementV1 { #[prost(message, optional, tag = "1")] @@ -504,7 +489,6 @@ pub mod stateful_order_event_v1 { } /// A stateful order removal contains the id of an order that was already /// placed and is now removed and the reason for the removal. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StatefulOrderRemovalV1 { #[prost(message, optional, tag = "1")] @@ -528,7 +512,6 @@ pub mod stateful_order_event_v1 { } /// A conditional order placement contains an order. The order is newly-placed /// and untriggered when this event is emitted. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConditionalOrderPlacementV1 { #[prost(message, optional, tag = "1")] @@ -548,7 +531,6 @@ pub mod stateful_order_event_v1 { } /// A conditional order trigger event contains an order id and is emitted when /// an order is triggered. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConditionalOrderTriggeredV1 { #[prost(message, optional, tag = "1")] @@ -569,7 +551,6 @@ pub mod stateful_order_event_v1 { } } /// A long term order placement contains an order. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LongTermOrderPlacementV1 { #[prost(message, optional, tag = "1")] @@ -587,11 +568,15 @@ pub mod stateful_order_event_v1 { .into() } } - /// A long term order placement contains an order. - #[allow(clippy::derive_partial_eq_without_eq)] + /// A long term order replacement contains an old order ID and the new order. #[derive(Clone, PartialEq, ::prost::Message)] pub struct LongTermOrderReplacementV1 { + /// vault replaces orders with a different order ID #[prost(message, optional, tag = "1")] + pub old_order_id: ::core::option::Option< + super::super::protocol::v1::IndexerOrderId, + >, + #[prost(message, optional, tag = "2")] pub order: ::core::option::Option, } impl ::prost::Name for LongTermOrderReplacementV1 { @@ -607,7 +592,6 @@ pub mod stateful_order_event_v1 { } } /// The type of event that this StatefulOrderEvent contains. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Event { /// Deprecated in favor of long_term_order_placement @@ -622,7 +606,7 @@ pub mod stateful_order_event_v1 { #[prost(message, tag = "7")] LongTermOrderPlacement(LongTermOrderPlacementV1), #[prost(message, tag = "8")] - OrderReplace(LongTermOrderReplacementV1), + OrderReplacement(LongTermOrderReplacementV1), } } impl ::prost::Name for StatefulOrderEventV1 { @@ -637,7 +621,6 @@ impl ::prost::Name for StatefulOrderEventV1 { } /// AssetCreateEventV1 message contains all the information about an new Asset on /// the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AssetCreateEventV1 { /// Unique, sequentially-generated. @@ -677,7 +660,6 @@ impl ::prost::Name for AssetCreateEventV1 { /// new Perpetual Market on the dYdX chain. /// Deprecated. See PerpetualMarketCreateEventV2 for the most up to date message /// for the event to create a new Perpetual Market. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualMarketCreateEventV1 { /// Unique Perpetual id. @@ -739,7 +721,6 @@ impl ::prost::Name for PerpetualMarketCreateEventV1 { } /// PerpetualMarketCreateEventV2 message contains all the information about a /// new Perpetual Market on the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualMarketCreateEventV2 { /// Unique Perpetual id. @@ -804,7 +785,6 @@ impl ::prost::Name for PerpetualMarketCreateEventV2 { } /// LiquidityTierUpsertEventV1 message contains all the information to /// create/update a Liquidity Tier on the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LiquidityTierUpsertEventV1 { /// Unique id. @@ -842,8 +822,7 @@ impl ::prost::Name for LiquidityTierUpsertEventV1 { } /// UpdateClobPairEventV1 message contains all the information about an update to /// a clob pair on the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct UpdateClobPairEventV1 { /// Unique clob pair Id associated with this perpetual market /// Defined in clob.clob_pair @@ -881,7 +860,6 @@ impl ::prost::Name for UpdateClobPairEventV1 { } /// UpdatePerpetualEventV1 message contains all the information about an update /// to a perpetual on the dYdX chain. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdatePerpetualEventV1 { /// Unique Perpetual id. @@ -920,7 +898,6 @@ impl ::prost::Name for UpdatePerpetualEventV1 { } /// TradingRewardsEventV1 is communicates all trading rewards for all accounts /// that receive trade rewards in the block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TradingRewardsEventV1 { /// The list of all trading rewards in the block. @@ -939,7 +916,6 @@ impl ::prost::Name for TradingRewardsEventV1 { } /// AddressTradingReward contains info on an instance of an address receiving a /// reward -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AddressTradingReward { /// The address of the wallet that will receive the trading reward. @@ -961,10 +937,9 @@ impl ::prost::Name for AddressTradingReward { } } /// OpenInterestUpdateEventV1 is used for open interest update events -#[allow(clippy::derive_partial_eq_without_eq)] +/// Deprecated. #[derive(Clone, PartialEq, ::prost::Message)] pub struct OpenInterestUpdateEventV1 { - /// The list of all open interest updates in the block. #[prost(message, repeated, tag = "1")] pub open_interest_updates: ::prost::alloc::vec::Vec, } @@ -979,10 +954,9 @@ impl ::prost::Name for OpenInterestUpdateEventV1 { } } /// OpenInterestUpdate contains a single open interest update for a perpetual -#[allow(clippy::derive_partial_eq_without_eq)] +/// Deprecated. #[derive(Clone, PartialEq, ::prost::Message)] pub struct OpenInterestUpdate { - /// The ID of the perpetual market. #[prost(uint32, tag = "1")] pub perpetual_id: u32, /// The new open interest value for the perpetual market. @@ -1002,7 +976,6 @@ impl ::prost::Name for OpenInterestUpdate { /// LiquidationEventV2 message contains all the information needed to update /// the liquidity tiers. It contains all the fields from V1 along with the /// open interest caps. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LiquidityTierUpsertEventV2 { /// Unique id. @@ -1044,3 +1017,46 @@ impl ::prost::Name for LiquidityTierUpsertEventV2 { "/dydxprotocol.indexer.events.LiquidityTierUpsertEventV2".into() } } +/// Event emitted when a referee is registered with an affiliate. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RegisterAffiliateEventV1 { + /// Address of the referee being registered. + #[prost(string, tag = "1")] + pub referee: ::prost::alloc::string::String, + /// Address of the affiliate associated with the referee. + #[prost(string, tag = "2")] + pub affiliate: ::prost::alloc::string::String, +} +impl ::prost::Name for RegisterAffiliateEventV1 { + const NAME: &'static str = "RegisterAffiliateEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.RegisterAffiliateEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.RegisterAffiliateEventV1".into() + } +} +/// Event emitted when a vault is created / updated. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpsertVaultEventV1 { + /// Address of the vault. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// Clob pair Id associated with the vault. + #[prost(uint32, tag = "2")] + pub clob_pair_id: u32, + /// Status of the vault. + #[prost(enumeration = "super::protocol::v1::VaultStatus", tag = "3")] + pub status: i32, +} +impl ::prost::Name for UpsertVaultEventV1 { + const NAME: &'static str = "UpsertVaultEventV1"; + const PACKAGE: &'static str = "dydxprotocol.indexer.events"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.events.UpsertVaultEventV1".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.events.UpsertVaultEventV1".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs b/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs index 4403e6bb5e..74375b3bbe 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.indexer_manager.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// IndexerTendermintEventWrapper is a wrapper around IndexerTendermintEvent, /// with an additional txn_hash field. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerTendermintEventWrapper { #[prost(message, optional, tag = "1")] @@ -21,7 +20,6 @@ impl ::prost::Name for IndexerTendermintEventWrapper { } /// IndexerEventsStoreValue represents the type of the value of the /// `IndexerEventsStore` in state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerEventsStoreValue { #[prost(message, repeated, tag = "1")] @@ -40,7 +38,6 @@ impl ::prost::Name for IndexerEventsStoreValue { /// IndexerTendermintEvent contains the base64 encoded event proto emitted from /// the dYdX application as well as additional metadata to determine the ordering /// of the event within the block and the subtype of the event. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerTendermintEvent { /// Subtype of the event e.g. "order_fill", "subaccount_update", etc. @@ -97,9 +94,9 @@ pub mod indexer_tendermint_event { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - BlockEvent::Unspecified => "BLOCK_EVENT_UNSPECIFIED", - BlockEvent::BeginBlock => "BLOCK_EVENT_BEGIN_BLOCK", - BlockEvent::EndBlock => "BLOCK_EVENT_END_BLOCK", + Self::Unspecified => "BLOCK_EVENT_UNSPECIFIED", + Self::BeginBlock => "BLOCK_EVENT_BEGIN_BLOCK", + Self::EndBlock => "BLOCK_EVENT_END_BLOCK", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -115,8 +112,7 @@ pub mod indexer_tendermint_event { /// ordering_within_block is either the transaction index or a boolean /// indicating the event was generated during processing the block rather than /// any specific transaction e.g. during FinalizeBlock. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum OrderingWithinBlock { #[prost(uint32, tag = "3")] TransactionIndex(u32), @@ -138,7 +134,6 @@ impl ::prost::Name for IndexerTendermintEvent { /// metadata for the block height, timestamp of the block and a list of all the /// hashes of the transactions within the block. The transaction hashes follow /// the ordering of the transactions as they appear within the block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerTendermintBlock { #[prost(uint32, tag = "1")] diff --git a/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs b/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs index 56dd4cda0a..6e83721315 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.off_chain_updates.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// OrderPlace messages contain the order placed/replaced. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderPlaceV1 { #[prost(message, optional, tag = "1")] @@ -53,11 +52,9 @@ pub mod order_place_v1 { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - OrderPlacementStatus::Unspecified => "ORDER_PLACEMENT_STATUS_UNSPECIFIED", - OrderPlacementStatus::BestEffortOpened => { - "ORDER_PLACEMENT_STATUS_BEST_EFFORT_OPENED" - } - OrderPlacementStatus::Opened => "ORDER_PLACEMENT_STATUS_OPENED", + Self::Unspecified => "ORDER_PLACEMENT_STATUS_UNSPECIFIED", + Self::BestEffortOpened => "ORDER_PLACEMENT_STATUS_BEST_EFFORT_OPENED", + Self::Opened => "ORDER_PLACEMENT_STATUS_OPENED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -85,7 +82,6 @@ impl ::prost::Name for OrderPlaceV1 { } /// OrderRemove messages contain the id of the order removed, the reason for the /// removal and the resulting status from the removal. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderRemoveV1 { #[prost(message, optional, tag = "1")] @@ -144,12 +140,10 @@ pub mod order_remove_v1 { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - OrderRemovalStatus::Unspecified => "ORDER_REMOVAL_STATUS_UNSPECIFIED", - OrderRemovalStatus::BestEffortCanceled => { - "ORDER_REMOVAL_STATUS_BEST_EFFORT_CANCELED" - } - OrderRemovalStatus::Canceled => "ORDER_REMOVAL_STATUS_CANCELED", - OrderRemovalStatus::Filled => "ORDER_REMOVAL_STATUS_FILLED", + Self::Unspecified => "ORDER_REMOVAL_STATUS_UNSPECIFIED", + Self::BestEffortCanceled => "ORDER_REMOVAL_STATUS_BEST_EFFORT_CANCELED", + Self::Canceled => "ORDER_REMOVAL_STATUS_CANCELED", + Self::Filled => "ORDER_REMOVAL_STATUS_FILLED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -178,7 +172,6 @@ impl ::prost::Name for OrderRemoveV1 { } /// OrderUpdate messages contain the id of the order being updated, and the /// updated total filled quantums of the order. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderUpdateV1 { #[prost(message, optional, tag = "1")] @@ -196,15 +189,17 @@ impl ::prost::Name for OrderUpdateV1 { "/dydxprotocol.indexer.off_chain_updates.OrderUpdateV1".into() } } -/// OrderReplace messages contain the replacement order. -#[allow(clippy::derive_partial_eq_without_eq)] +/// OrderReplace messages contain the old order ID and the replacement order. #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderReplaceV1 { + /// vault replaces orders with a different order ID #[prost(message, optional, tag = "1")] + pub old_order_id: ::core::option::Option, + #[prost(message, optional, tag = "2")] pub order: ::core::option::Option, - #[prost(enumeration = "order_place_v1::OrderPlacementStatus", tag = "2")] + #[prost(enumeration = "order_place_v1::OrderPlacementStatus", tag = "3")] pub placement_status: i32, - #[prost(message, optional, tag = "3")] + #[prost(message, optional, tag = "4")] pub time_stamp: ::core::option::Option<::prost_types::Timestamp>, } impl ::prost::Name for OrderReplaceV1 { @@ -219,7 +214,6 @@ impl ::prost::Name for OrderReplaceV1 { } /// An OffChainUpdate message is the message type which will be sent on Kafka to /// the Indexer. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OffChainUpdateV1 { /// Contains one of an OrderPlaceV1, OrderRemoveV1, OrderUpdateV1, and @@ -231,7 +225,6 @@ pub struct OffChainUpdateV1 { pub mod off_chain_update_v1 { /// Contains one of an OrderPlaceV1, OrderRemoveV1, OrderUpdateV1, and /// OrderReplaceV1 message. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum UpdateMessage { #[prost(message, tag = "1")] diff --git a/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs b/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs index b25016f4af..2744eaab2f 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.protocol.v1.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// IndexerSubaccountId defines a unique identifier for a Subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerSubaccountId { /// The address of the wallet that owns this subaccount. @@ -23,7 +22,6 @@ impl ::prost::Name for IndexerSubaccountId { } /// IndexerPerpetualPosition are an account’s positions of a `Perpetual`. /// Therefore they hold any information needed to trade perpetuals. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerPerpetualPosition { /// The `Id` of the `Perpetual`. @@ -55,7 +53,6 @@ impl ::prost::Name for IndexerPerpetualPosition { } /// IndexerAssetPosition define an account’s positions of an `Asset`. /// Therefore they hold any information needed to trade on Spot and Margin. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerAssetPosition { /// The `Id` of the `Asset`. @@ -81,7 +78,6 @@ impl ::prost::Name for IndexerAssetPosition { } } /// IndexerOrderId refers to a single order belonging to a Subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerOrderId { /// The subaccount ID that opened this order. @@ -127,7 +123,6 @@ impl ::prost::Name for IndexerOrderId { } /// IndexerOrderV1 represents a single order belonging to a `Subaccount` /// for a particular `ClobPair`. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexerOrder { /// The unique ID of this order. Meant to be unique across all orders. @@ -205,9 +200,9 @@ pub mod indexer_order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Side::Unspecified => "SIDE_UNSPECIFIED", - Side::Buy => "SIDE_BUY", - Side::Sell => "SIDE_SELL", + Self::Unspecified => "SIDE_UNSPECIFIED", + Self::Buy => "SIDE_BUY", + Self::Sell => "SIDE_SELL", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -261,10 +256,10 @@ pub mod indexer_order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - TimeInForce::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", - TimeInForce::Ioc => "TIME_IN_FORCE_IOC", - TimeInForce::PostOnly => "TIME_IN_FORCE_POST_ONLY", - TimeInForce::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", + Self::Unspecified => "TIME_IN_FORCE_UNSPECIFIED", + Self::Ioc => "TIME_IN_FORCE_IOC", + Self::PostOnly => "TIME_IN_FORCE_POST_ONLY", + Self::FillOrKill => "TIME_IN_FORCE_FILL_OR_KILL", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -310,9 +305,9 @@ pub mod indexer_order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - ConditionType::Unspecified => "CONDITION_TYPE_UNSPECIFIED", - ConditionType::StopLoss => "CONDITION_TYPE_STOP_LOSS", - ConditionType::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", + Self::Unspecified => "CONDITION_TYPE_UNSPECIFIED", + Self::StopLoss => "CONDITION_TYPE_STOP_LOSS", + Self::TakeProfit => "CONDITION_TYPE_TAKE_PROFIT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -326,8 +321,7 @@ pub mod indexer_order { } } /// Information about when the order expires. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum GoodTilOneof { /// The last block this order can be executed at (after which it will be /// unfillable). Used only for Short-Term orders. If this value is non-zero @@ -391,13 +385,13 @@ impl ClobPairStatus { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - ClobPairStatus::Unspecified => "CLOB_PAIR_STATUS_UNSPECIFIED", - ClobPairStatus::Active => "CLOB_PAIR_STATUS_ACTIVE", - ClobPairStatus::Paused => "CLOB_PAIR_STATUS_PAUSED", - ClobPairStatus::CancelOnly => "CLOB_PAIR_STATUS_CANCEL_ONLY", - ClobPairStatus::PostOnly => "CLOB_PAIR_STATUS_POST_ONLY", - ClobPairStatus::Initializing => "CLOB_PAIR_STATUS_INITIALIZING", - ClobPairStatus::FinalSettlement => "CLOB_PAIR_STATUS_FINAL_SETTLEMENT", + Self::Unspecified => "CLOB_PAIR_STATUS_UNSPECIFIED", + Self::Active => "CLOB_PAIR_STATUS_ACTIVE", + Self::Paused => "CLOB_PAIR_STATUS_PAUSED", + Self::CancelOnly => "CLOB_PAIR_STATUS_CANCEL_ONLY", + Self::PostOnly => "CLOB_PAIR_STATUS_POST_ONLY", + Self::Initializing => "CLOB_PAIR_STATUS_INITIALIZING", + Self::FinalSettlement => "CLOB_PAIR_STATUS_FINAL_SETTLEMENT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -433,9 +427,9 @@ impl PerpetualMarketType { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - PerpetualMarketType::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", - PerpetualMarketType::Cross => "PERPETUAL_MARKET_TYPE_CROSS", - PerpetualMarketType::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", + Self::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", + Self::Cross => "PERPETUAL_MARKET_TYPE_CROSS", + Self::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -448,3 +442,44 @@ impl PerpetualMarketType { } } } +/// VaultStatus represents the status of a vault. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VaultStatus { + /// Default value, invalid and unused. + Unspecified = 0, + /// Don’t place orders. Does not count toward global vault balances. + Deactivated = 1, + /// Don’t place orders. Does count towards global vault balances. + StandBy = 2, + /// Places orders on both sides of the book. + Quoting = 3, + /// Only place orders that close the position. + CloseOnly = 4, +} +impl VaultStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VAULT_STATUS_UNSPECIFIED", + Self::Deactivated => "VAULT_STATUS_DEACTIVATED", + Self::StandBy => "VAULT_STATUS_STAND_BY", + Self::Quoting => "VAULT_STATUS_QUOTING", + Self::CloseOnly => "VAULT_STATUS_CLOSE_ONLY", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VAULT_STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "VAULT_STATUS_DEACTIVATED" => Some(Self::Deactivated), + "VAULT_STATUS_STAND_BY" => Some(Self::StandBy), + "VAULT_STATUS_QUOTING" => Some(Self::Quoting), + "VAULT_STATUS_CLOSE_ONLY" => Some(Self::CloseOnly), + _ => None, + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.indexer.redis.rs b/v4-proto-rs/src/dydxprotocol.indexer.redis.rs index bdb1bdccc3..934c9ab15d 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.redis.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.redis.rs @@ -2,7 +2,6 @@ /// RedisOrder is a proto for orders stored in Redis. This proto holds some /// human-readable values such as price, size and ticker as well as the original /// `Order` proto from the dYdX application. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RedisOrder { /// uuid of the Order generated by the Indexer based on the `OrderId`. @@ -55,9 +54,9 @@ pub mod redis_order { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - TickerType::Unspecified => "TICKER_TYPE_UNSPECIFIED", - TickerType::Perpetual => "TICKER_TYPE_PERPETUAL", - TickerType::Spot => "TICKER_TYPE_SPOT", + Self::Unspecified => "TICKER_TYPE_UNSPECIFIED", + Self::Perpetual => "TICKER_TYPE_PERPETUAL", + Self::Spot => "TICKER_TYPE_SPOT", } } /// Creates an enum from field names used in the ProtoBuf definition. diff --git a/v4-proto-rs/src/dydxprotocol.indexer.shared.rs b/v4-proto-rs/src/dydxprotocol.indexer.shared.rs index 570398f54b..69dd782553 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.shared.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.shared.rs @@ -60,34 +60,28 @@ impl OrderRemovalReason { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - OrderRemovalReason::Unspecified => "ORDER_REMOVAL_REASON_UNSPECIFIED", - OrderRemovalReason::Expired => "ORDER_REMOVAL_REASON_EXPIRED", - OrderRemovalReason::UserCanceled => "ORDER_REMOVAL_REASON_USER_CANCELED", - OrderRemovalReason::Undercollateralized => { - "ORDER_REMOVAL_REASON_UNDERCOLLATERALIZED" - } - OrderRemovalReason::InternalError => "ORDER_REMOVAL_REASON_INTERNAL_ERROR", - OrderRemovalReason::SelfTradeError => "ORDER_REMOVAL_REASON_SELF_TRADE_ERROR", - OrderRemovalReason::PostOnlyWouldCrossMakerOrder => { + Self::Unspecified => "ORDER_REMOVAL_REASON_UNSPECIFIED", + Self::Expired => "ORDER_REMOVAL_REASON_EXPIRED", + Self::UserCanceled => "ORDER_REMOVAL_REASON_USER_CANCELED", + Self::Undercollateralized => "ORDER_REMOVAL_REASON_UNDERCOLLATERALIZED", + Self::InternalError => "ORDER_REMOVAL_REASON_INTERNAL_ERROR", + Self::SelfTradeError => "ORDER_REMOVAL_REASON_SELF_TRADE_ERROR", + Self::PostOnlyWouldCrossMakerOrder => { "ORDER_REMOVAL_REASON_POST_ONLY_WOULD_CROSS_MAKER_ORDER" } - OrderRemovalReason::ImmediateOrCancelWouldRestOnBook => { + Self::ImmediateOrCancelWouldRestOnBook => { "ORDER_REMOVAL_REASON_IMMEDIATE_OR_CANCEL_WOULD_REST_ON_BOOK" } - OrderRemovalReason::FokOrderCouldNotBeFullyFulled => { + Self::FokOrderCouldNotBeFullyFulled => { "ORDER_REMOVAL_REASON_FOK_ORDER_COULD_NOT_BE_FULLY_FULLED" } - OrderRemovalReason::ReduceOnlyResize => { - "ORDER_REMOVAL_REASON_REDUCE_ONLY_RESIZE" - } - OrderRemovalReason::IndexerExpired => "ORDER_REMOVAL_REASON_INDEXER_EXPIRED", - OrderRemovalReason::Replaced => "ORDER_REMOVAL_REASON_REPLACED", - OrderRemovalReason::FullyFilled => "ORDER_REMOVAL_REASON_FULLY_FILLED", - OrderRemovalReason::EquityTier => "ORDER_REMOVAL_REASON_EQUITY_TIER", - OrderRemovalReason::FinalSettlement => { - "ORDER_REMOVAL_REASON_FINAL_SETTLEMENT" - } - OrderRemovalReason::ViolatesIsolatedSubaccountConstraints => { + Self::ReduceOnlyResize => "ORDER_REMOVAL_REASON_REDUCE_ONLY_RESIZE", + Self::IndexerExpired => "ORDER_REMOVAL_REASON_INDEXER_EXPIRED", + Self::Replaced => "ORDER_REMOVAL_REASON_REPLACED", + Self::FullyFilled => "ORDER_REMOVAL_REASON_FULLY_FILLED", + Self::EquityTier => "ORDER_REMOVAL_REASON_EQUITY_TIER", + Self::FinalSettlement => "ORDER_REMOVAL_REASON_FINAL_SETTLEMENT", + Self::ViolatesIsolatedSubaccountConstraints => { "ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS" } } diff --git a/v4-proto-rs/src/dydxprotocol.indexer.socks.rs b/v4-proto-rs/src/dydxprotocol.indexer.socks.rs index b664937294..09999d1bef 100644 --- a/v4-proto-rs/src/dydxprotocol.indexer.socks.rs +++ b/v4-proto-rs/src/dydxprotocol.indexer.socks.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// Message to be sent through the 'to-websockets-orderbooks` kafka topic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OrderbookMessage { /// Stringified JSON object of all events to be streamed. @@ -24,7 +23,6 @@ impl ::prost::Name for OrderbookMessage { } } /// Message to be sent through the 'to-websockets-subaccounts` kafka topic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SubaccountMessage { /// Block height where the contents occur. @@ -57,7 +55,6 @@ impl ::prost::Name for SubaccountMessage { } } /// Message to be sent through the 'to-websockets-trades` kafka topic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TradeMessage { /// Block height where the contents occur. @@ -84,7 +81,6 @@ impl ::prost::Name for TradeMessage { } } /// Message to be sent through the 'to-websockets-markets` kafka topic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketMessage { /// Stringified JSON object of all events to be streamed. @@ -105,7 +101,6 @@ impl ::prost::Name for MarketMessage { } } /// Message to be sent through the 'to-websockets-candles` kafka topic. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CandleMessage { /// Stringified JSON object of all events to be streamed. @@ -160,13 +155,13 @@ pub mod candle_message { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Resolution::OneMinute => "ONE_MINUTE", - Resolution::FiveMinutes => "FIVE_MINUTES", - Resolution::FifteenMinutes => "FIFTEEN_MINUTES", - Resolution::ThirtyMinutes => "THIRTY_MINUTES", - Resolution::OneHour => "ONE_HOUR", - Resolution::FourHours => "FOUR_HOURS", - Resolution::OneDay => "ONE_DAY", + Self::OneMinute => "ONE_MINUTE", + Self::FiveMinutes => "FIVE_MINUTES", + Self::FifteenMinutes => "FIFTEEN_MINUTES", + Self::ThirtyMinutes => "THIRTY_MINUTES", + Self::OneHour => "ONE_HOUR", + Self::FourHours => "FOUR_HOURS", + Self::OneDay => "ONE_DAY", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -194,3 +189,26 @@ impl ::prost::Name for CandleMessage { "/dydxprotocol.indexer.socks.CandleMessage".into() } } +/// Message to be sent through the 'to-websockets-block-height` kafka topic. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockHeightMessage { + /// Block height where the contents occur. + #[prost(string, tag = "1")] + pub block_height: ::prost::alloc::string::String, + /// ISO formatted time of the block height. + #[prost(string, tag = "2")] + pub time: ::prost::alloc::string::String, + /// Version of the websocket message. + #[prost(string, tag = "3")] + pub version: ::prost::alloc::string::String, +} +impl ::prost::Name for BlockHeightMessage { + const NAME: &'static str = "BlockHeightMessage"; + const PACKAGE: &'static str = "dydxprotocol.indexer.socks"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.indexer.socks.BlockHeightMessage".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.indexer.socks.BlockHeightMessage".into() + } +} diff --git a/v4-proto-rs/src/dydxprotocol.listing.rs b/v4-proto-rs/src/dydxprotocol.listing.rs new file mode 100644 index 0000000000..c1f3b7747e --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.listing.rs @@ -0,0 +1,538 @@ +// This file is @generated by prost-build. +/// ListingVaultDepositParams represents the params for PML megavault deposits +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListingVaultDepositParams { + /// Amount that will be deposited into the new market vault exclusively + #[prost(bytes = "vec", tag = "1")] + pub new_vault_deposit_amount: ::prost::alloc::vec::Vec, + /// Amount deposited into the main vault exclusively. This amount does not + /// include the amount deposited into the new vault. + #[prost(bytes = "vec", tag = "2")] + pub main_vault_deposit_amount: ::prost::alloc::vec::Vec, + /// Lockup period for this deposit + #[prost(uint32, tag = "3")] + pub num_blocks_to_lock_shares: u32, +} +impl ::prost::Name for ListingVaultDepositParams { + const NAME: &'static str = "ListingVaultDepositParams"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.ListingVaultDepositParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.ListingVaultDepositParams".into() + } +} +/// GenesisState defines `x/listing`'s genesis state. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// hard_cap_for_markets is the hard cap for the number of markets that can be + /// listed + #[prost(uint32, tag = "1")] + pub hard_cap_for_markets: u32, + /// listing_vault_deposit_params is the params for PML megavault deposits + #[prost(message, optional, tag = "2")] + pub listing_vault_deposit_params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.GenesisState".into() + } +} +/// Queries for the hard cap on listed markets +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMarketsHardCap {} +impl ::prost::Name for QueryMarketsHardCap { + const NAME: &'static str = "QueryMarketsHardCap"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.QueryMarketsHardCap".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.QueryMarketsHardCap".into() + } +} +/// Response type indicating the hard cap on listed markets +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMarketsHardCapResponse { + #[prost(uint32, tag = "1")] + pub hard_cap: u32, +} +impl ::prost::Name for QueryMarketsHardCapResponse { + const NAME: &'static str = "QueryMarketsHardCapResponse"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.QueryMarketsHardCapResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.QueryMarketsHardCapResponse".into() + } +} +/// Queries the listing vault deposit params +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryListingVaultDepositParams {} +impl ::prost::Name for QueryListingVaultDepositParams { + const NAME: &'static str = "QueryListingVaultDepositParams"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.QueryListingVaultDepositParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.QueryListingVaultDepositParams".into() + } +} +/// Response type for QueryListingVaultDepositParams +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryListingVaultDepositParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryListingVaultDepositParamsResponse { + const NAME: &'static str = "QueryListingVaultDepositParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.QueryListingVaultDepositParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.QueryListingVaultDepositParamsResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries for the hard cap number of listed markets + pub async fn markets_hard_cap( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.listing.Query/MarketsHardCap", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.listing.Query", "MarketsHardCap")); + self.inner.unary(req, path, codec).await + } + /// Queries the listing vault deposit params + pub async fn listing_vault_deposit_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.listing.Query/ListingVaultDepositParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.listing.Query", + "ListingVaultDepositParams", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgSetMarketsHardCap is used to set a hard cap on the number of markets +/// listed +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetMarketsHardCap { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Hard cap for the total number of markets listed + #[prost(uint32, tag = "2")] + pub hard_cap_for_markets: u32, +} +impl ::prost::Name for MsgSetMarketsHardCap { + const NAME: &'static str = "MsgSetMarketsHardCap"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgSetMarketsHardCap".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgSetMarketsHardCap".into() + } +} +/// MsgSetMarketsHardCapResponse defines the MsgSetMarketsHardCap response +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetMarketsHardCapResponse {} +impl ::prost::Name for MsgSetMarketsHardCapResponse { + const NAME: &'static str = "MsgSetMarketsHardCapResponse"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgSetMarketsHardCapResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgSetMarketsHardCapResponse".into() + } +} +/// MsgCreateMarketPermissionless is a message used to create new markets without +/// going through x/gov +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgCreateMarketPermissionless { + /// The name of the `Perpetual` (e.g. `BTC-USD`). + #[prost(string, tag = "1")] + pub ticker: ::prost::alloc::string::String, + /// The subaccount to deposit from. + #[prost(message, optional, tag = "2")] + pub subaccount_id: ::core::option::Option, +} +impl ::prost::Name for MsgCreateMarketPermissionless { + const NAME: &'static str = "MsgCreateMarketPermissionless"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgCreateMarketPermissionless".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgCreateMarketPermissionless".into() + } +} +/// MsgCreateMarketPermissionlessResponse defines the +/// MsgCreateMarketPermissionless response +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgCreateMarketPermissionlessResponse {} +impl ::prost::Name for MsgCreateMarketPermissionlessResponse { + const NAME: &'static str = "MsgCreateMarketPermissionlessResponse"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgCreateMarketPermissionlessResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgCreateMarketPermissionlessResponse".into() + } +} +/// MsgSetListingVaultDepositParams is a message used to set PML megavault +/// deposit params +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetListingVaultDepositParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Params which define the vault deposit for market listing + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgSetListingVaultDepositParams { + const NAME: &'static str = "MsgSetListingVaultDepositParams"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgSetListingVaultDepositParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgSetListingVaultDepositParams".into() + } +} +/// MsgSetListingVaultDepositParamsResponse defines the +/// MsgSetListingVaultDepositParams response +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetListingVaultDepositParamsResponse {} +impl ::prost::Name for MsgSetListingVaultDepositParamsResponse { + const NAME: &'static str = "MsgSetListingVaultDepositParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.listing"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SetMarketsHardCap sets a hard cap on the number of markets listed + pub async fn set_markets_hard_cap( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.listing.Msg/SetMarketsHardCap", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.listing.Msg", "SetMarketsHardCap"), + ); + self.inner.unary(req, path, codec).await + } + /// CreateMarketPermissionless creates a new market without going through x/gov + pub async fn create_market_permissionless( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.listing.Msg/CreateMarketPermissionless", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.listing.Msg", + "CreateMarketPermissionless", + ), + ); + self.inner.unary(req, path, codec).await + } + /// SetListingVaultDepositParams sets PML megavault deposit params + pub async fn set_listing_vault_deposit_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.listing.Msg/SetListingVaultDepositParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.listing.Msg", + "SetListingVaultDepositParams", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.perpetuals.rs b/v4-proto-rs/src/dydxprotocol.perpetuals.rs index 7fd52a2abb..9f683f6193 100644 --- a/v4-proto-rs/src/dydxprotocol.perpetuals.rs +++ b/v4-proto-rs/src/dydxprotocol.perpetuals.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// Perpetual represents a perpetual on the dYdX exchange. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Perpetual { /// PerpetualParams is the parameters of the perpetual. @@ -26,7 +25,6 @@ impl ::prost::Name for Perpetual { } /// PerpetualParams represents the parameters of a perpetual on the dYdX /// exchange. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualParams { /// Unique, sequentially-generated. @@ -68,7 +66,6 @@ impl ::prost::Name for PerpetualParams { } } /// MarketPremiums stores a list of premiums for a single perpetual market. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketPremiums { /// perpetual_id is the Id of the perpetual market. @@ -96,7 +93,6 @@ impl ::prost::Name for MarketPremiums { /// values for that market. /// This struct can either be used to store `PremiumVotes` or /// `PremiumSamples`. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PremiumStore { /// all_market_premiums a list of `MarketPremiums`, each corresponding to @@ -123,7 +119,6 @@ impl ::prost::Name for PremiumStore { } } /// LiquidityTier stores margin information. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LiquidityTier { /// Unique id. @@ -194,9 +189,9 @@ impl PerpetualMarketType { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - PerpetualMarketType::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", - PerpetualMarketType::Cross => "PERPETUAL_MARKET_TYPE_CROSS", - PerpetualMarketType::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", + Self::Unspecified => "PERPETUAL_MARKET_TYPE_UNSPECIFIED", + Self::Cross => "PERPETUAL_MARKET_TYPE_CROSS", + Self::Isolated => "PERPETUAL_MARKET_TYPE_ISOLATED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -210,8 +205,7 @@ impl PerpetualMarketType { } } /// Params defines the parameters for x/perpetuals module. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Params { /// Funding rate clamp factor in parts-per-million, used for clamping 8-hour /// funding rates according to equation: |R| <= funding_rate_clamp_factor * @@ -239,7 +233,6 @@ impl ::prost::Name for Params { } } /// GenesisState defines the perpetuals module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, repeated, tag = "1")] @@ -260,8 +253,7 @@ impl ::prost::Name for GenesisState { } } /// Queries a Perpetual by id. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPerpetualRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -277,7 +269,6 @@ impl ::prost::Name for QueryPerpetualRequest { } } /// QueryPerpetualResponse is response type for the Perpetual RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryPerpetualResponse { #[prost(message, optional, tag = "1")] @@ -294,7 +285,6 @@ impl ::prost::Name for QueryPerpetualResponse { } } /// Queries a list of Perpetual items. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllPerpetualsRequest { #[prost(message, optional, tag = "1")] @@ -313,7 +303,6 @@ impl ::prost::Name for QueryAllPerpetualsRequest { } } /// QueryAllPerpetualsResponse is response type for the AllPerpetuals RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllPerpetualsResponse { #[prost(message, repeated, tag = "1")] @@ -334,7 +323,6 @@ impl ::prost::Name for QueryAllPerpetualsResponse { } } /// Queries a list of LiquidityTier items. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllLiquidityTiersRequest { #[prost(message, optional, tag = "1")] @@ -354,7 +342,6 @@ impl ::prost::Name for QueryAllLiquidityTiersRequest { } /// QueryAllLiquidityTiersResponse is response type for the AllLiquidityTiers RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllLiquidityTiersResponse { #[prost(message, repeated, tag = "1")] @@ -375,8 +362,7 @@ impl ::prost::Name for QueryAllLiquidityTiersResponse { } } /// QueryPremiumVotesRequest is the request type for the PremiumVotes RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPremiumVotesRequest {} impl ::prost::Name for QueryPremiumVotesRequest { const NAME: &'static str = "QueryPremiumVotesRequest"; @@ -390,7 +376,6 @@ impl ::prost::Name for QueryPremiumVotesRequest { } /// QueryPremiumVotesResponse is the response type for the PremiumVotes RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryPremiumVotesResponse { #[prost(message, optional, tag = "1")] @@ -408,8 +393,7 @@ impl ::prost::Name for QueryPremiumVotesResponse { } /// QueryPremiumSamplesRequest is the request type for the PremiumSamples RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryPremiumSamplesRequest {} impl ::prost::Name for QueryPremiumSamplesRequest { const NAME: &'static str = "QueryPremiumSamplesRequest"; @@ -423,7 +407,6 @@ impl ::prost::Name for QueryPremiumSamplesRequest { } /// QueryPremiumSamplesResponse is the response type for the PremiumSamples RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryPremiumSamplesResponse { #[prost(message, optional, tag = "1")] @@ -440,8 +423,7 @@ impl ::prost::Name for QueryPremiumSamplesResponse { } } /// QueryParamsResponse is the response type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsRequest {} impl ::prost::Name for QueryParamsRequest { const NAME: &'static str = "QueryParamsRequest"; @@ -454,8 +436,7 @@ impl ::prost::Name for QueryParamsRequest { } } /// QueryParamsResponse is the response type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsResponse { #[prost(message, optional, tag = "1")] pub params: ::core::option::Option, @@ -472,7 +453,13 @@ impl ::prost::Name for QueryParamsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -480,6 +467,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -495,8 +483,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -521,7 +509,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -568,8 +556,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -594,8 +581,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -622,8 +608,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -650,8 +635,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -678,8 +662,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -706,8 +689,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -723,7 +705,6 @@ pub mod query_client { } } /// MsgCreatePerpetual is a message used by x/gov to create a new perpetual. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCreatePerpetual { /// The address that controls the module. @@ -745,8 +726,7 @@ impl ::prost::Name for MsgCreatePerpetual { } /// MsgCreatePerpetualResponse defines the CreatePerpetual /// response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCreatePerpetualResponse {} impl ::prost::Name for MsgCreatePerpetualResponse { const NAME: &'static str = "MsgCreatePerpetualResponse"; @@ -760,7 +740,6 @@ impl ::prost::Name for MsgCreatePerpetualResponse { } /// MsgSetLiquidityTier is a message used by x/gov to create or update a /// liquidity tier. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSetLiquidityTier { /// The address that controls the module. @@ -781,8 +760,7 @@ impl ::prost::Name for MsgSetLiquidityTier { } } /// MsgSetLiquidityTierResponse defines the SetLiquidityTier response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgSetLiquidityTierResponse {} impl ::prost::Name for MsgSetLiquidityTierResponse { const NAME: &'static str = "MsgSetLiquidityTierResponse"; @@ -796,7 +774,6 @@ impl ::prost::Name for MsgSetLiquidityTierResponse { } /// MsgUpdatePerpetualParams is a message used by x/gov to update the parameters /// of a perpetual. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdatePerpetualParams { #[prost(string, tag = "1")] @@ -817,8 +794,7 @@ impl ::prost::Name for MsgUpdatePerpetualParams { } /// MsgUpdatePerpetualParamsResponse defines the UpdatePerpetualParams /// response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdatePerpetualParamsResponse {} impl ::prost::Name for MsgUpdatePerpetualParamsResponse { const NAME: &'static str = "MsgUpdatePerpetualParamsResponse"; @@ -832,8 +808,7 @@ impl ::prost::Name for MsgUpdatePerpetualParamsResponse { } /// FundingPremium represents a funding premium value for a perpetual /// market. Can be used to represent a premium vote or a premium sample. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct FundingPremium { /// The id of the perpetual market. #[prost(uint32, tag = "1")] @@ -853,7 +828,6 @@ impl ::prost::Name for FundingPremium { } } /// MsgAddPremiumVotes is a request type for the AddPremiumVotes method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgAddPremiumVotes { #[prost(message, repeated, tag = "1")] @@ -871,8 +845,7 @@ impl ::prost::Name for MsgAddPremiumVotes { } /// MsgAddPremiumVotesResponse defines the AddPremiumVotes /// response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgAddPremiumVotesResponse {} impl ::prost::Name for MsgAddPremiumVotesResponse { const NAME: &'static str = "MsgAddPremiumVotesResponse"; @@ -886,7 +859,6 @@ impl ::prost::Name for MsgAddPremiumVotesResponse { } /// MsgUpdateParams is a message used by x/gov to update the parameters of the /// perpetuals module. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateParams { #[prost(string, tag = "1")] @@ -906,8 +878,7 @@ impl ::prost::Name for MsgUpdateParams { } } /// MsgUpdateParamsResponse defines the UpdateParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateParamsResponse {} impl ::prost::Name for MsgUpdateParamsResponse { const NAME: &'static str = "MsgUpdateParamsResponse"; @@ -921,7 +892,13 @@ impl ::prost::Name for MsgUpdateParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -929,6 +906,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -944,8 +922,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -970,7 +948,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -1018,8 +996,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1046,8 +1023,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1075,8 +1051,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1103,8 +1078,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -1134,8 +1108,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.prices.rs b/v4-proto-rs/src/dydxprotocol.prices.rs index a62d3cf018..f0ce9775d2 100644 --- a/v4-proto-rs/src/dydxprotocol.prices.rs +++ b/v4-proto-rs/src/dydxprotocol.prices.rs @@ -3,7 +3,6 @@ /// representing price values, resolving markets on individual exchanges, and /// generating price updates. This configuration is specific to the quote /// currency. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MarketParam { /// Unique, sequentially-generated value. @@ -16,10 +15,15 @@ pub struct MarketParam { /// For example if `Exponent == -5` then a `Value` of `1,000,000,000` /// represents ``$10,000`. Therefore `10 ^ Exponent` represents the smallest /// price step (in dollars) that can be recorded. + /// + /// Deprecated since v8.x. This value is now determined from the marketmap. + #[deprecated] #[prost(sint32, tag = "3")] pub exponent: i32, /// The minimum number of exchanges that should be reporting a live price for /// a price update to be considered valid. + /// + /// Deprecated since v8.x. This value is now determined from the marketmap. #[prost(uint32, tag = "4")] pub min_exchanges: u32, /// The minimum allowable change in `price` value that would cause a price @@ -28,6 +32,8 @@ pub struct MarketParam { pub min_price_change_ppm: u32, /// A string of json that encodes the configuration for resolving the price /// of this market on various exchanges. + /// + /// Deprecated since v8.x. This is now determined from the marketmap. #[prost(string, tag = "6")] pub exchange_config_json: ::prost::alloc::string::String, } @@ -42,14 +48,16 @@ impl ::prost::Name for MarketParam { } } /// MarketPrice is used by the application to store/retrieve oracle price. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MarketPrice { /// Unique, sequentially-generated value that matches `MarketParam`. #[prost(uint32, tag = "1")] pub id: u32, /// Static value. The exponent of the price. See the comment on the duplicate /// MarketParam field for more information. + /// + /// As of v7.1.x, this value is determined from the marketmap instead of + /// needing to match the MarketParam field. #[prost(sint32, tag = "2")] pub exponent: i32, /// The variable value that is updated by oracle price updates. `0` if it has @@ -68,7 +76,6 @@ impl ::prost::Name for MarketPrice { } } /// GenesisState defines the prices module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, repeated, tag = "1")] @@ -88,8 +95,7 @@ impl ::prost::Name for GenesisState { } /// QueryMarketPriceRequest is request type for the Query/Params `MarketPrice` /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryMarketPriceRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -106,8 +112,7 @@ impl ::prost::Name for QueryMarketPriceRequest { } /// QueryMarketPriceResponse is response type for the Query/Params `MarketPrice` /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryMarketPriceResponse { #[prost(message, optional, tag = "1")] pub market_price: ::core::option::Option, @@ -124,7 +129,6 @@ impl ::prost::Name for QueryMarketPriceResponse { } /// QueryAllMarketPricesRequest is request type for the Query/Params /// `AllMarketPrices` RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllMarketPricesRequest { #[prost(message, optional, tag = "1")] @@ -144,7 +148,6 @@ impl ::prost::Name for QueryAllMarketPricesRequest { } /// QueryAllMarketPricesResponse is response type for the Query/Params /// `AllMarketPrices` RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllMarketPricesResponse { #[prost(message, repeated, tag = "1")] @@ -166,8 +169,7 @@ impl ::prost::Name for QueryAllMarketPricesResponse { } /// QueryMarketParamsRequest is request type for the Query/Params `MarketParams` /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryMarketParamRequest { #[prost(uint32, tag = "1")] pub id: u32, @@ -184,7 +186,6 @@ impl ::prost::Name for QueryMarketParamRequest { } /// QueryMarketParamResponse is response type for the Query/Params `MarketParams` /// RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryMarketParamResponse { #[prost(message, optional, tag = "1")] @@ -202,7 +203,6 @@ impl ::prost::Name for QueryMarketParamResponse { } /// QueryAllMarketParamsRequest is request type for the Query/Params /// `AllMarketParams` RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllMarketParamsRequest { #[prost(message, optional, tag = "1")] @@ -222,7 +222,6 @@ impl ::prost::Name for QueryAllMarketParamsRequest { } /// QueryAllMarketParamsResponse is response type for the Query/Params /// `AllMarketParams` RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllMarketParamsResponse { #[prost(message, repeated, tag = "1")] @@ -244,7 +243,13 @@ impl ::prost::Name for QueryAllMarketParamsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -252,6 +257,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -267,8 +273,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -293,7 +299,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -340,8 +346,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -366,8 +371,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -392,8 +396,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -418,8 +421,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -436,7 +438,6 @@ pub mod query_client { } /// MsgCreateOracleMarket is a message used by x/gov for creating a new oracle /// market. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCreateOracleMarket { /// The address that controls the module. @@ -457,8 +458,7 @@ impl ::prost::Name for MsgCreateOracleMarket { } } /// MsgCreateOracleMarketResponse defines the CreateOracleMarket response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCreateOracleMarketResponse {} impl ::prost::Name for MsgCreateOracleMarketResponse { const NAME: &'static str = "MsgCreateOracleMarketResponse"; @@ -471,7 +471,6 @@ impl ::prost::Name for MsgCreateOracleMarketResponse { } } /// MsgUpdateMarketPrices is a request type for the UpdateMarketPrices method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateMarketPrices { #[prost(message, repeated, tag = "1")] @@ -482,8 +481,7 @@ pub struct MsgUpdateMarketPrices { /// Nested message and enum types in `MsgUpdateMarketPrices`. pub mod msg_update_market_prices { /// MarketPrice represents a price update for a single market - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MarketPrice { /// The id of market to update #[prost(uint32, tag = "1")] @@ -515,8 +513,7 @@ impl ::prost::Name for MsgUpdateMarketPrices { } /// MsgUpdateMarketPricesResponse defines the MsgUpdateMarketPrices response /// type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateMarketPricesResponse {} impl ::prost::Name for MsgUpdateMarketPricesResponse { const NAME: &'static str = "MsgUpdateMarketPricesResponse"; @@ -530,7 +527,6 @@ impl ::prost::Name for MsgUpdateMarketPricesResponse { } /// MsgUpdateMarketParam is a message used by x/gov for updating the parameters /// of an oracle market. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateMarketParam { #[prost(string, tag = "1")] @@ -550,8 +546,7 @@ impl ::prost::Name for MsgUpdateMarketParam { } } /// MsgUpdateMarketParamResponse defines the UpdateMarketParam response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateMarketParamResponse {} impl ::prost::Name for MsgUpdateMarketParamResponse { const NAME: &'static str = "MsgUpdateMarketParamResponse"; @@ -565,7 +560,13 @@ impl ::prost::Name for MsgUpdateMarketParamResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -573,6 +574,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -588,8 +590,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -614,7 +616,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -662,8 +664,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -690,8 +691,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -719,8 +719,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.ratelimit.rs b/v4-proto-rs/src/dydxprotocol.ratelimit.rs index d243ba3c70..a927d43ad3 100644 --- a/v4-proto-rs/src/dydxprotocol.ratelimit.rs +++ b/v4-proto-rs/src/dydxprotocol.ratelimit.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// LimitParams defines rate limit params on a denom. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LimitParams { /// denom is the denomination of the token being rate limited. @@ -23,7 +22,6 @@ impl ::prost::Name for LimitParams { } } /// Limiter defines one rate-limiter on a specfic denom. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Limiter { /// period is the rolling time period for which the limit applies @@ -52,7 +50,6 @@ impl ::prost::Name for Limiter { } } /// DenomCapacity stores a list of rate limit capacity for a denom. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DenomCapacity { /// denom is the denomination of the token being rate limited. @@ -76,7 +73,6 @@ impl ::prost::Name for DenomCapacity { } } /// LimiterCapacity contains a pair of limiter and its corresponding capacity. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LimiterCapacity { #[prost(message, optional, tag = "1")] @@ -95,7 +91,6 @@ impl ::prost::Name for LimiterCapacity { } } /// GenesisState defines the ratelimit module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// limit_params_list defines the list of `LimitParams` at genesis. @@ -114,7 +109,6 @@ impl ::prost::Name for GenesisState { } /// PendingSendPacket contains the channel_id and sequence pair to identify a /// pending packet -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PendingSendPacket { #[prost(string, tag = "1")] @@ -133,8 +127,7 @@ impl ::prost::Name for PendingSendPacket { } } /// ListLimitParamsRequest is a request type of the ListLimitParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ListLimitParamsRequest {} impl ::prost::Name for ListLimitParamsRequest { const NAME: &'static str = "ListLimitParamsRequest"; @@ -147,7 +140,6 @@ impl ::prost::Name for ListLimitParamsRequest { } } /// ListLimitParamsResponse is a response type of the ListLimitParams RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListLimitParamsResponse { #[prost(message, repeated, tag = "1")] @@ -165,7 +157,6 @@ impl ::prost::Name for ListLimitParamsResponse { } /// QueryCapacityByDenomRequest is a request type for the CapacityByDenom RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryCapacityByDenomRequest { #[prost(string, tag = "1")] @@ -183,7 +174,6 @@ impl ::prost::Name for QueryCapacityByDenomRequest { } /// QueryCapacityByDenomResponse is a response type of the CapacityByDenom RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryCapacityByDenomResponse { #[prost(message, repeated, tag = "1")] @@ -201,8 +191,7 @@ impl ::prost::Name for QueryCapacityByDenomResponse { } /// QueryAllPendingSendPacketsRequest is a request type for the /// AllPendingSendPackets RPC -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryAllPendingSendPacketsRequest {} impl ::prost::Name for QueryAllPendingSendPacketsRequest { const NAME: &'static str = "QueryAllPendingSendPacketsRequest"; @@ -216,7 +205,6 @@ impl ::prost::Name for QueryAllPendingSendPacketsRequest { } /// QueryAllPendingSendPacketsResponse is a response type of the /// AllPendingSendPackets RPC -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllPendingSendPacketsResponse { #[prost(message, repeated, tag = "1")] @@ -234,7 +222,13 @@ impl ::prost::Name for QueryAllPendingSendPacketsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -242,6 +236,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -257,8 +252,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -283,7 +278,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -330,8 +325,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -358,8 +352,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -386,8 +379,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -408,7 +400,6 @@ pub mod query_client { } } /// MsgSetLimitParams is the Msg/SetLimitParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSetLimitParams { #[prost(string, tag = "1")] @@ -428,8 +419,7 @@ impl ::prost::Name for MsgSetLimitParams { } } /// MsgSetLimitParamsResponse is the Msg/SetLimitParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgSetLimitParamsResponse {} impl ::prost::Name for MsgSetLimitParamsResponse { const NAME: &'static str = "MsgSetLimitParamsResponse"; @@ -443,7 +433,13 @@ impl ::prost::Name for MsgSetLimitParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -451,6 +447,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -466,8 +463,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -492,7 +489,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -539,8 +536,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.revshare.rs b/v4-proto-rs/src/dydxprotocol.revshare.rs new file mode 100644 index 0000000000..928c683d74 --- /dev/null +++ b/v4-proto-rs/src/dydxprotocol.revshare.rs @@ -0,0 +1,671 @@ +// This file is @generated by prost-build. +/// MarketMappeRevenueShareParams represents params for the above message +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarketMapperRevenueShareParams { + /// The address which will receive the revenue share payouts + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// The fraction of the fees which will go to the above mentioned address. + /// In parts-per-million + #[prost(uint32, tag = "2")] + pub revenue_share_ppm: u32, + /// This parameter defines how many days post market initiation will the + /// revenue share be applied for. After valid_days from market initiation + /// the revenue share goes down to 0 + #[prost(uint32, tag = "3")] + pub valid_days: u32, +} +impl ::prost::Name for MarketMapperRevenueShareParams { + const NAME: &'static str = "MarketMapperRevenueShareParams"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MarketMapperRevenueShareParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MarketMapperRevenueShareParams".into() + } +} +/// GenesisState defines `x/revshare`'s genesis state. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for GenesisState { + const NAME: &'static str = "GenesisState"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.GenesisState".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.GenesisState".into() + } +} +/// MarketMapperRevShareDetails specifies any details associated with the market +/// mapper revenue share +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MarketMapperRevShareDetails { + /// Unix timestamp recorded when the market revenue share expires + #[prost(uint64, tag = "1")] + pub expiration_ts: u64, +} +impl ::prost::Name for MarketMapperRevShareDetails { + const NAME: &'static str = "MarketMapperRevShareDetails"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MarketMapperRevShareDetails".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MarketMapperRevShareDetails".into() + } +} +/// UnconditionalRevShareConfig stores recipients that +/// receive a share of net revenue unconditionally. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UnconditionalRevShareConfig { + /// Configs for each recipient. + #[prost(message, repeated, tag = "1")] + pub configs: ::prost::alloc::vec::Vec< + unconditional_rev_share_config::RecipientConfig, + >, +} +/// Nested message and enum types in `UnconditionalRevShareConfig`. +pub mod unconditional_rev_share_config { + /// Describes the config of a recipient + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct RecipientConfig { + /// Address of the recepient. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// Percentage of net revenue to share with recipient, in parts-per-million. + #[prost(uint32, tag = "2")] + pub share_ppm: u32, + } + impl ::prost::Name for RecipientConfig { + const NAME: &'static str = "RecipientConfig"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.UnconditionalRevShareConfig.RecipientConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.UnconditionalRevShareConfig.RecipientConfig".into() + } + } +} +impl ::prost::Name for UnconditionalRevShareConfig { + const NAME: &'static str = "UnconditionalRevShareConfig"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.UnconditionalRevShareConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.UnconditionalRevShareConfig".into() + } +} +/// Queries for the default market mapper revenue share params +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMarketMapperRevenueShareParams {} +impl ::prost::Name for QueryMarketMapperRevenueShareParams { + const NAME: &'static str = "QueryMarketMapperRevenueShareParams"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryMarketMapperRevenueShareParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryMarketMapperRevenueShareParams".into() + } +} +/// Response type for QueryMarketMapperRevenueShareParams +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMarketMapperRevenueShareParamsResponse { + #[prost(message, optional, tag = "1")] + pub params: ::core::option::Option, +} +impl ::prost::Name for QueryMarketMapperRevenueShareParamsResponse { + const NAME: &'static str = "QueryMarketMapperRevenueShareParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryMarketMapperRevenueShareParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryMarketMapperRevenueShareParamsResponse".into() + } +} +/// Queries market mapper revenue share details for a specific market +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMarketMapperRevShareDetails { + #[prost(uint32, tag = "1")] + pub market_id: u32, +} +impl ::prost::Name for QueryMarketMapperRevShareDetails { + const NAME: &'static str = "QueryMarketMapperRevShareDetails"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryMarketMapperRevShareDetails".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryMarketMapperRevShareDetails".into() + } +} +/// Response type for QueryMarketMapperRevShareDetails +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMarketMapperRevShareDetailsResponse { + #[prost(message, optional, tag = "1")] + pub details: ::core::option::Option, +} +impl ::prost::Name for QueryMarketMapperRevShareDetailsResponse { + const NAME: &'static str = "QueryMarketMapperRevShareDetailsResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryMarketMapperRevShareDetailsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryMarketMapperRevShareDetailsResponse".into() + } +} +/// Queries unconditional revenue share details +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryUnconditionalRevShareConfig {} +impl ::prost::Name for QueryUnconditionalRevShareConfig { + const NAME: &'static str = "QueryUnconditionalRevShareConfig"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryUnconditionalRevShareConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryUnconditionalRevShareConfig".into() + } +} +/// Response type for QueryUnconditionalRevShareConfig +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryUnconditionalRevShareConfigResponse { + #[prost(message, optional, tag = "1")] + pub config: ::core::option::Option, +} +impl ::prost::Name for QueryUnconditionalRevShareConfigResponse { + const NAME: &'static str = "QueryUnconditionalRevShareConfigResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.QueryUnconditionalRevShareConfigResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.QueryUnconditionalRevShareConfigResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// MarketMapperRevenueShareParams queries the revenue share params for the + /// market mapper + pub async fn market_mapper_revenue_share_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Query/MarketMapperRevenueShareParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Query", + "MarketMapperRevenueShareParams", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries market mapper revenue share details for a specific market + pub async fn market_mapper_rev_share_details( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Query/MarketMapperRevShareDetails", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Query", + "MarketMapperRevShareDetails", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries unconditional revenue share config + pub async fn unconditional_rev_share_config( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Query/UnconditionalRevShareConfig", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Query", + "UnconditionalRevShareConfig", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Message to set the market mapper revenue share +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetMarketMapperRevenueShare { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Parameters for the revenue share + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgSetMarketMapperRevenueShare { + const NAME: &'static str = "MsgSetMarketMapperRevenueShare"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgSetMarketMapperRevenueShare".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgSetMarketMapperRevenueShare".into() + } +} +/// Response to a MsgSetMarketMapperRevenueShare +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetMarketMapperRevenueShareResponse {} +impl ::prost::Name for MsgSetMarketMapperRevenueShareResponse { + const NAME: &'static str = "MsgSetMarketMapperRevenueShareResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgSetMarketMapperRevenueShareResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgSetMarketMapperRevenueShareResponse".into() + } +} +/// Msg to set market mapper revenue share details (e.g. expiration timestamp) +/// for a specific market. To be used as an override for existing revenue share +/// settings set by the MsgSetMarketMapperRevenueShare msg +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetMarketMapperRevShareDetailsForMarket { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The market ID for which to set the revenue share details + #[prost(uint32, tag = "2")] + pub market_id: u32, + /// Parameters for the revenue share details + #[prost(message, optional, tag = "3")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgSetMarketMapperRevShareDetailsForMarket { + const NAME: &'static str = "MsgSetMarketMapperRevShareDetailsForMarket"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgSetMarketMapperRevShareDetailsForMarket".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgSetMarketMapperRevShareDetailsForMarket".into() + } +} +/// Response to a MsgSetMarketMapperRevShareDetailsForMarket +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetMarketMapperRevShareDetailsForMarketResponse {} +impl ::prost::Name for MsgSetMarketMapperRevShareDetailsForMarketResponse { + const NAME: &'static str = "MsgSetMarketMapperRevShareDetailsForMarketResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgSetMarketMapperRevShareDetailsForMarketResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgSetMarketMapperRevShareDetailsForMarketResponse" + .into() + } +} +/// Message to update the unconditional revenue share config. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateUnconditionalRevShareConfig { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The config to update. + #[prost(message, optional, tag = "2")] + pub config: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateUnconditionalRevShareConfig { + const NAME: &'static str = "MsgUpdateUnconditionalRevShareConfig"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgUpdateUnconditionalRevShareConfig".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgUpdateUnconditionalRevShareConfig".into() + } +} +/// Response to MsgUpdateUnconditionalRevShareConfig +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgUpdateUnconditionalRevShareConfigResponse {} +impl ::prost::Name for MsgUpdateUnconditionalRevShareConfigResponse { + const NAME: &'static str = "MsgUpdateUnconditionalRevShareConfigResponse"; + const PACKAGE: &'static str = "dydxprotocol.revshare"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.revshare.MsgUpdateUnconditionalRevShareConfigResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.revshare.MsgUpdateUnconditionalRevShareConfigResponse".into() + } +} +/// Generated client implementations. +pub mod msg_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Msg defines the Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SetMarketMapperRevenueShare sets the revenue share for a market + /// mapper. + pub async fn set_market_mapper_revenue_share( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Msg/SetMarketMapperRevenueShare", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Msg", + "SetMarketMapperRevenueShare", + ), + ); + self.inner.unary(req, path, codec).await + } + /// SetMarketMapperRevenueShareDetails sets the revenue share details for a + /// market mapper. + pub async fn set_market_mapper_rev_share_details_for_market( + &mut self, + request: impl tonic::IntoRequest< + super::MsgSetMarketMapperRevShareDetailsForMarket, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Msg/SetMarketMapperRevShareDetailsForMarket", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Msg", + "SetMarketMapperRevShareDetailsForMarket", + ), + ); + self.inner.unary(req, path, codec).await + } + /// UpdateUnconditionalRevShareConfig sets the unconditional revshare config + pub async fn update_unconditional_rev_share_config( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.revshare.Msg/UpdateUnconditionalRevShareConfig", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.revshare.Msg", + "UpdateUnconditionalRevShareConfig", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/v4-proto-rs/src/dydxprotocol.rewards.rs b/v4-proto-rs/src/dydxprotocol.rewards.rs index ec3a05e69f..3f4b88ae33 100644 --- a/v4-proto-rs/src/dydxprotocol.rewards.rs +++ b/v4-proto-rs/src/dydxprotocol.rewards.rs @@ -1,6 +1,5 @@ // This file is @generated by prost-build. /// Params defines the parameters for x/rewards module. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Params { /// The module account to distribute rewards from. @@ -34,7 +33,6 @@ impl ::prost::Name for Params { } } /// GenesisState defines the rewards module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// The parameters of the module. @@ -52,8 +50,7 @@ impl ::prost::Name for GenesisState { } } /// QueryParamsRequest is a request type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsRequest {} impl ::prost::Name for QueryParamsRequest { const NAME: &'static str = "QueryParamsRequest"; @@ -66,7 +63,6 @@ impl ::prost::Name for QueryParamsRequest { } } /// QueryParamsResponse is a response type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryParamsResponse { #[prost(message, optional, tag = "1")] @@ -84,7 +80,13 @@ impl ::prost::Name for QueryParamsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -92,6 +94,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -107,8 +110,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -133,7 +136,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -180,8 +183,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -198,7 +200,6 @@ pub mod query_client { } /// RewardShare stores the relative weight of rewards that each address is /// entitled to. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RewardShare { #[prost(string, tag = "1")] @@ -217,7 +218,6 @@ impl ::prost::Name for RewardShare { } } /// MsgUpdateParams is the Msg/UpdateParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateParams { #[prost(string, tag = "1")] @@ -237,8 +237,7 @@ impl ::prost::Name for MsgUpdateParams { } } /// MsgUpdateParamsResponse is the Msg/UpdateParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateParamsResponse {} impl ::prost::Name for MsgUpdateParamsResponse { const NAME: &'static str = "MsgUpdateParamsResponse"; @@ -252,7 +251,13 @@ impl ::prost::Name for MsgUpdateParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -260,6 +265,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -275,8 +281,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -301,7 +307,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -348,8 +354,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.sending.rs b/v4-proto-rs/src/dydxprotocol.sending.rs index 7a3bb775b0..a22ff14c4b 100644 --- a/v4-proto-rs/src/dydxprotocol.sending.rs +++ b/v4-proto-rs/src/dydxprotocol.sending.rs @@ -2,8 +2,7 @@ /// GenesisState defines the sending module's genesis state. /// /// this line is used by starport scaffolding # genesis/proto/state -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GenesisState {} impl ::prost::Name for GenesisState { const NAME: &'static str = "GenesisState"; @@ -17,7 +16,13 @@ impl ::prost::Name for GenesisState { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -25,6 +30,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -40,8 +46,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -66,7 +72,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -104,7 +110,6 @@ pub mod query_client { } } /// Transfer represents a single transfer between two subaccounts. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Transfer { /// The sender subaccount ID. @@ -132,7 +137,6 @@ impl ::prost::Name for Transfer { } /// MsgDepositToSubaccount represents a single transfer from an `x/bank` /// account to an `x/subaccounts` subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgDepositToSubaccount { /// The sender wallet address. @@ -160,7 +164,6 @@ impl ::prost::Name for MsgDepositToSubaccount { } /// MsgWithdrawFromSubaccount represents a single transfer from an /// `x/subaccounts` subaccount to an `x/bank` account. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgWithdrawFromSubaccount { /// The sender subaccount ID. @@ -190,7 +193,6 @@ impl ::prost::Name for MsgWithdrawFromSubaccount { /// to an `x/bank` account (can be either a module account address or a user /// account address). /// Should only be executed by governance. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSendFromModuleToAccount { #[prost(string, tag = "1")] @@ -217,7 +219,6 @@ impl ::prost::Name for MsgSendFromModuleToAccount { } } /// MsgCreateTransfer is a request type used for initiating new transfers. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCreateTransfer { #[prost(message, optional, tag = "1")] @@ -234,8 +235,7 @@ impl ::prost::Name for MsgCreateTransfer { } } /// MsgCreateTransferResponse is a response type used for new transfers. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgCreateTransferResponse {} impl ::prost::Name for MsgCreateTransferResponse { const NAME: &'static str = "MsgCreateTransferResponse"; @@ -249,8 +249,7 @@ impl ::prost::Name for MsgCreateTransferResponse { } /// MsgDepositToSubaccountResponse is a response type used for new /// account-to-subaccount transfers. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgDepositToSubaccountResponse {} impl ::prost::Name for MsgDepositToSubaccountResponse { const NAME: &'static str = "MsgDepositToSubaccountResponse"; @@ -264,8 +263,7 @@ impl ::prost::Name for MsgDepositToSubaccountResponse { } /// MsgWithdrawFromSubaccountResponse is a response type used for new /// subaccount-to-account transfers. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgWithdrawFromSubaccountResponse {} impl ::prost::Name for MsgWithdrawFromSubaccountResponse { const NAME: &'static str = "MsgWithdrawFromSubaccountResponse"; @@ -279,8 +277,7 @@ impl ::prost::Name for MsgWithdrawFromSubaccountResponse { } /// MsgSendFromModuleToAccountResponse is a response type used for new /// module-to-account transfers. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgSendFromModuleToAccountResponse {} impl ::prost::Name for MsgSendFromModuleToAccountResponse { const NAME: &'static str = "MsgSendFromModuleToAccountResponse"; @@ -294,7 +291,13 @@ impl ::prost::Name for MsgSendFromModuleToAccountResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -302,6 +305,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -317,8 +321,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -343,7 +347,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -390,8 +394,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -417,8 +420,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -446,8 +448,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -475,8 +476,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.stats.rs b/v4-proto-rs/src/dydxprotocol.stats.rs index 68ec458964..f58d910812 100644 --- a/v4-proto-rs/src/dydxprotocol.stats.rs +++ b/v4-proto-rs/src/dydxprotocol.stats.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// Params defines the parameters for x/stats module. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Params { /// The desired number of seconds in the look-back window. #[prost(message, optional, tag = "1")] @@ -18,8 +17,7 @@ impl ::prost::Name for Params { } } /// GenesisState defines the stats module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GenesisState { /// The parameters of the module. #[prost(message, optional, tag = "1")] @@ -36,7 +34,6 @@ impl ::prost::Name for GenesisState { } } /// BlockStats is used to store stats transiently within the scope of a block. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockStats { /// The fills that occured on this block. @@ -46,7 +43,6 @@ pub struct BlockStats { /// Nested message and enum types in `BlockStats`. pub mod block_stats { /// Fill records data about a fill on this block. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Fill { /// Taker wallet address @@ -81,8 +77,7 @@ impl ::prost::Name for BlockStats { } } /// StatsMetadata stores metadata for the x/stats module -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct StatsMetadata { /// The oldest epoch that is included in the stats. The next epoch to be /// removed from the window. @@ -100,7 +95,6 @@ impl ::prost::Name for StatsMetadata { } } /// EpochStats stores stats for a particular epoch -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EpochStats { /// Epoch end time @@ -113,7 +107,6 @@ pub struct EpochStats { /// Nested message and enum types in `EpochStats`. pub mod epoch_stats { /// A user and its associated stats - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UserWithStats { #[prost(string, tag = "1")] @@ -143,8 +136,7 @@ impl ::prost::Name for EpochStats { } } /// GlobalStats stores global stats -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GlobalStats { /// Notional USDC traded in quantums #[prost(uint64, tag = "1")] @@ -161,8 +153,7 @@ impl ::prost::Name for GlobalStats { } } /// UserStats stores stats for a User -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct UserStats { /// Taker USDC in quantums #[prost(uint64, tag = "1")] @@ -181,9 +172,29 @@ impl ::prost::Name for UserStats { "/dydxprotocol.stats.UserStats".into() } } -/// QueryParamsRequest is a request type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] +/// CachedStakeAmount stores the last calculated total staked amount for address #[derive(Clone, PartialEq, ::prost::Message)] +pub struct CachedStakeAmount { + /// Last calculated total staked amount by the delegator (in coin amount). + #[prost(bytes = "vec", tag = "1")] + pub staked_amount: ::prost::alloc::vec::Vec, + /// Block time at which the calculation is cached (in Unix Epoch seconds) + /// Rounded down to nearest second. + #[prost(int64, tag = "2")] + pub cached_at: i64, +} +impl ::prost::Name for CachedStakeAmount { + const NAME: &'static str = "CachedStakeAmount"; + const PACKAGE: &'static str = "dydxprotocol.stats"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.stats.CachedStakeAmount".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.stats.CachedStakeAmount".into() + } +} +/// QueryParamsRequest is a request type for the Params RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsRequest {} impl ::prost::Name for QueryParamsRequest { const NAME: &'static str = "QueryParamsRequest"; @@ -196,8 +207,7 @@ impl ::prost::Name for QueryParamsRequest { } } /// QueryParamsResponse is a response type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsResponse { #[prost(message, optional, tag = "1")] pub params: ::core::option::Option, @@ -213,8 +223,7 @@ impl ::prost::Name for QueryParamsResponse { } } /// QueryStatsMetadataRequest is a request type for the StatsMetadata RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryStatsMetadataRequest {} impl ::prost::Name for QueryStatsMetadataRequest { const NAME: &'static str = "QueryStatsMetadataRequest"; @@ -228,8 +237,7 @@ impl ::prost::Name for QueryStatsMetadataRequest { } /// QueryStatsMetadataResponse is a response type for the StatsMetadata RPC /// method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryStatsMetadataResponse { #[prost(message, optional, tag = "1")] pub metadata: ::core::option::Option, @@ -245,8 +253,7 @@ impl ::prost::Name for QueryStatsMetadataResponse { } } /// QueryGlobalStatsRequest is a request type for the GlobalStats RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryGlobalStatsRequest {} impl ::prost::Name for QueryGlobalStatsRequest { const NAME: &'static str = "QueryGlobalStatsRequest"; @@ -259,8 +266,7 @@ impl ::prost::Name for QueryGlobalStatsRequest { } } /// QueryGlobalStatsResponse is a response type for the GlobalStats RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryGlobalStatsResponse { #[prost(message, optional, tag = "1")] pub stats: ::core::option::Option, @@ -276,7 +282,6 @@ impl ::prost::Name for QueryGlobalStatsResponse { } } /// QueryUserStatsRequest is a request type for the UserStats RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryUserStatsRequest { #[prost(string, tag = "1")] @@ -293,8 +298,7 @@ impl ::prost::Name for QueryUserStatsRequest { } } /// QueryUserStatsResponse is a request type for the UserStats RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryUserStatsResponse { #[prost(message, optional, tag = "1")] pub stats: ::core::option::Option, @@ -311,7 +315,13 @@ impl ::prost::Name for QueryUserStatsResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -319,6 +329,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -334,8 +345,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -360,7 +371,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -407,8 +418,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -433,8 +443,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -459,8 +468,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -485,8 +493,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -502,7 +509,6 @@ pub mod query_client { } } /// MsgUpdateParams is the Msg/UpdateParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgUpdateParams { #[prost(string, tag = "1")] @@ -522,8 +528,7 @@ impl ::prost::Name for MsgUpdateParams { } } /// MsgUpdateParamsResponse is the Msg/UpdateParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgUpdateParamsResponse {} impl ::prost::Name for MsgUpdateParamsResponse { const NAME: &'static str = "MsgUpdateParamsResponse"; @@ -537,7 +542,13 @@ impl ::prost::Name for MsgUpdateParamsResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -545,6 +556,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -560,8 +572,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -586,7 +598,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -633,8 +645,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.subaccounts.rs b/v4-proto-rs/src/dydxprotocol.subaccounts.rs index f08f01ff77..6e2454fdf4 100644 --- a/v4-proto-rs/src/dydxprotocol.subaccounts.rs +++ b/v4-proto-rs/src/dydxprotocol.subaccounts.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// AssetPositions define an account’s positions of an `Asset`. /// Therefore they hold any information needed to trade on Spot and Margin. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AssetPosition { /// The `Id` of the `Asset`. @@ -28,7 +27,6 @@ impl ::prost::Name for AssetPosition { } /// PerpetualPositions are an account’s positions of a `Perpetual`. /// Therefore they hold any information needed to trade perpetuals. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PerpetualPosition { /// The `Id` of the `Perpetual`. @@ -41,6 +39,9 @@ pub struct PerpetualPosition { /// settled. #[prost(bytes = "vec", tag = "3")] pub funding_index: ::prost::alloc::vec::Vec, + /// The quote_balance of the `Perpetual`. + #[prost(bytes = "vec", tag = "4")] + pub quote_balance: ::prost::alloc::vec::Vec, } impl ::prost::Name for PerpetualPosition { const NAME: &'static str = "PerpetualPosition"; @@ -53,7 +54,6 @@ impl ::prost::Name for PerpetualPosition { } } /// SubaccountId defines a unique identifier for a Subaccount. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SubaccountId { /// The address of the wallet that owns this subaccount. @@ -76,7 +76,6 @@ impl ::prost::Name for SubaccountId { } /// Subaccount defines a single sub-account for a given address. /// Subaccounts are uniquely indexed by a subaccountNumber/owner pair. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Subaccount { /// The Id of the Subaccount @@ -105,8 +104,83 @@ impl ::prost::Name for Subaccount { "/dydxprotocol.subaccounts.Subaccount".into() } } +/// StreamSubaccountUpdate provides information on a subaccount update. Used in +/// the full node GRPC stream. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StreamSubaccountUpdate { + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// updated_perpetual_positions will each be for unique perpetuals. + #[prost(message, repeated, tag = "2")] + pub updated_perpetual_positions: ::prost::alloc::vec::Vec< + SubaccountPerpetualPosition, + >, + /// updated_asset_positions will each be for unique assets. + #[prost(message, repeated, tag = "3")] + pub updated_asset_positions: ::prost::alloc::vec::Vec, + /// Snapshot indicates if the response is from a snapshot of the subaccount. + /// All updates should be ignored until snapshot is received. + /// If the snapshot is true, then all previous entries should be + /// discarded and the subaccount should be resynced. + /// For a snapshot subaccount update, the `updated_perpetual_positions` and + /// `updated_asset_positions` fields will contain the full state of the + /// subaccount. + #[prost(bool, tag = "4")] + pub snapshot: bool, +} +impl ::prost::Name for StreamSubaccountUpdate { + const NAME: &'static str = "StreamSubaccountUpdate"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.StreamSubaccountUpdate".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.StreamSubaccountUpdate".into() + } +} +/// SubaccountPerpetualPosition provides information on a subaccount's updated +/// perpetual positions. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct SubaccountPerpetualPosition { + /// The `Id` of the `Perpetual`. + #[prost(uint32, tag = "1")] + pub perpetual_id: u32, + /// The size of the position in base quantums. Negative means short. + #[prost(int64, tag = "2")] + pub quantums: i64, +} +impl ::prost::Name for SubaccountPerpetualPosition { + const NAME: &'static str = "SubaccountPerpetualPosition"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.SubaccountPerpetualPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.SubaccountPerpetualPosition".into() + } +} +/// SubaccountAssetPosition provides information on a subaccount's updated asset +/// positions. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct SubaccountAssetPosition { + /// The `Id` of the `Asset`. + #[prost(uint32, tag = "1")] + pub asset_id: u32, + /// The absolute size of the position in base quantums. + #[prost(uint64, tag = "2")] + pub quantums: u64, +} +impl ::prost::Name for SubaccountAssetPosition { + const NAME: &'static str = "SubaccountAssetPosition"; + const PACKAGE: &'static str = "dydxprotocol.subaccounts"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.subaccounts.SubaccountAssetPosition".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.subaccounts.SubaccountAssetPosition".into() + } +} /// GenesisState defines the subaccounts module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { #[prost(message, repeated, tag = "1")] @@ -123,7 +197,6 @@ impl ::prost::Name for GenesisState { } } /// QueryGetSubaccountRequest is request type for the Query RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryGetSubaccountRequest { #[prost(string, tag = "1")] @@ -142,7 +215,6 @@ impl ::prost::Name for QueryGetSubaccountRequest { } } /// QuerySubaccountResponse is response type for the Query RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QuerySubaccountResponse { #[prost(message, optional, tag = "1")] @@ -159,7 +231,6 @@ impl ::prost::Name for QuerySubaccountResponse { } } /// QueryAllSubaccountRequest is request type for the Query RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllSubaccountRequest { #[prost(message, optional, tag = "1")] @@ -178,7 +249,6 @@ impl ::prost::Name for QueryAllSubaccountRequest { } } /// QuerySubaccountAllResponse is response type for the Query RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QuerySubaccountAllResponse { #[prost(message, repeated, tag = "1")] @@ -201,8 +271,7 @@ impl ::prost::Name for QuerySubaccountAllResponse { /// QueryGetWithdrawalAndTransfersBlockedInfoRequest is a request type for /// fetching information about whether withdrawals and transfers are blocked for /// a collateral pool associated with the passed in perpetual id. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryGetWithdrawalAndTransfersBlockedInfoRequest { #[prost(uint32, tag = "1")] pub perpetual_id: u32, @@ -221,8 +290,7 @@ impl ::prost::Name for QueryGetWithdrawalAndTransfersBlockedInfoRequest { } /// QueryGetWithdrawalAndTransfersBlockedInfoRequest is a response type for /// fetching information about whether withdrawals and transfers are blocked. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryGetWithdrawalAndTransfersBlockedInfoResponse { #[prost(uint32, tag = "1")] pub negative_tnc_subaccount_seen_at_block: u32, @@ -246,8 +314,7 @@ impl ::prost::Name for QueryGetWithdrawalAndTransfersBlockedInfoResponse { /// QueryCollateralPoolAddressRequest is the request type for fetching the /// account address of the collateral pool associated with the passed in /// perpetual id. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryCollateralPoolAddressRequest { #[prost(uint32, tag = "1")] pub perpetual_id: u32, @@ -265,7 +332,6 @@ impl ::prost::Name for QueryCollateralPoolAddressRequest { /// QueryCollateralPoolAddressResponse is a response type for fetching the /// account address of the collateral pool associated with the passed in /// perpetual id. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryCollateralPoolAddressResponse { #[prost(string, tag = "1")] @@ -283,7 +349,13 @@ impl ::prost::Name for QueryCollateralPoolAddressResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -291,6 +363,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -306,8 +379,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -332,7 +405,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -379,8 +452,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -405,8 +477,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -436,8 +507,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -467,8 +537,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/dydxprotocol.vault.rs b/v4-proto-rs/src/dydxprotocol.vault.rs index 9cf8e3d256..74d5479b67 100644 --- a/v4-proto-rs/src/dydxprotocol.vault.rs +++ b/v4-proto-rs/src/dydxprotocol.vault.rs @@ -1,6 +1,198 @@ // This file is @generated by prost-build. -/// Params stores `x/vault` parameters. -#[allow(clippy::derive_partial_eq_without_eq)] +/// VaultId uniquely identifies a vault by its type and number. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct VaultId { + /// Type of the vault. + #[prost(enumeration = "VaultType", tag = "1")] + pub r#type: i32, + /// Unique ID of the vault within above type. + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for VaultId { + const NAME: &'static str = "VaultId"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.VaultId".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.VaultId".into() + } +} +/// VaultType represents different types of vaults. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VaultType { + /// Default value, invalid and unused. + Unspecified = 0, + /// Vault is associated with a CLOB pair. + Clob = 1, +} +impl VaultType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VAULT_TYPE_UNSPECIFIED", + Self::Clob => "VAULT_TYPE_CLOB", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VAULT_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "VAULT_TYPE_CLOB" => Some(Self::Clob), + _ => None, + } + } +} +/// VaultStatus represents the status of a vault. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VaultStatus { + /// Default value, invalid and unused. + Unspecified = 0, + /// Don’t place orders. Does not count toward global vault balances. + /// A vault can only be set to this status if its equity is non-positive. + Deactivated = 1, + /// Don’t place orders. Does count towards global vault balances. + StandBy = 2, + /// Places orders on both sides of the book. + Quoting = 3, + /// Only place orders that close the position. + CloseOnly = 4, +} +impl VaultStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VAULT_STATUS_UNSPECIFIED", + Self::Deactivated => "VAULT_STATUS_DEACTIVATED", + Self::StandBy => "VAULT_STATUS_STAND_BY", + Self::Quoting => "VAULT_STATUS_QUOTING", + Self::CloseOnly => "VAULT_STATUS_CLOSE_ONLY", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VAULT_STATUS_UNSPECIFIED" => Some(Self::Unspecified), + "VAULT_STATUS_DEACTIVATED" => Some(Self::Deactivated), + "VAULT_STATUS_STAND_BY" => Some(Self::StandBy), + "VAULT_STATUS_QUOTING" => Some(Self::Quoting), + "VAULT_STATUS_CLOSE_ONLY" => Some(Self::CloseOnly), + _ => None, + } + } +} +/// QuotingParams stores vault quoting parameters. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuotingParams { + /// The number of layers of orders a vault places. For example if + /// `layers=2`, a vault places 2 asks and 2 bids. + #[prost(uint32, tag = "1")] + pub layers: u32, + /// The minimum base spread when a vault quotes around reservation price. + #[prost(uint32, tag = "2")] + pub spread_min_ppm: u32, + /// The buffer amount to add to min_price_change_ppm to arrive at `spread` + /// according to formula: + /// `spread = max(spread_min_ppm, min_price_change_ppm + spread_buffer_ppm)`. + #[prost(uint32, tag = "3")] + pub spread_buffer_ppm: u32, + /// The factor that determines how aggressive a vault skews its orders. + #[prost(uint32, tag = "4")] + pub skew_factor_ppm: u32, + /// The percentage of vault equity that each order is sized at. + #[prost(uint32, tag = "5")] + pub order_size_pct_ppm: u32, + /// The duration that a vault's orders are valid for. + #[prost(uint32, tag = "6")] + pub order_expiration_seconds: u32, + /// The number of quote quantums in quote asset that a vault with no perpetual + /// positions must have to activate, i.e. if a vault has no perpetual positions + /// and has strictly less than this amount of quote asset, it will not + /// activate. + #[prost(bytes = "vec", tag = "7")] + pub activation_threshold_quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QuotingParams { + const NAME: &'static str = "QuotingParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QuotingParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QuotingParams".into() + } +} +/// VaultParams stores vault parameters. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VaultParams { + /// Status of the vault. + #[prost(enumeration = "VaultStatus", tag = "1")] + pub status: i32, + /// Quoting parameters of the vault. + #[prost(message, optional, tag = "2")] + pub quoting_params: ::core::option::Option, +} +impl ::prost::Name for VaultParams { + const NAME: &'static str = "VaultParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.VaultParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.VaultParams".into() + } +} +/// OperatorParams stores parameters regarding megavault operator. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OperatorParams { + /// Address of the operator. + #[prost(string, tag = "1")] + pub operator: ::prost::alloc::string::String, + /// Metadata of the operator. + #[prost(message, optional, tag = "2")] + pub metadata: ::core::option::Option, +} +impl ::prost::Name for OperatorParams { + const NAME: &'static str = "OperatorParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.OperatorParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.OperatorParams".into() + } +} +/// OperatorMetadata stores metadata regarding megavault operator. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OperatorMetadata { + /// Name of the operator. + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + /// Description of the operator. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, +} +impl ::prost::Name for OperatorMetadata { + const NAME: &'static str = "OperatorMetadata"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.OperatorMetadata".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.OperatorMetadata".into() + } +} +/// Deprecated: Params stores `x/vault` parameters. +/// Deprecated since v6.x as is replaced by QuotingParams. #[derive(Clone, PartialEq, ::prost::Message)] pub struct Params { /// The number of layers of orders a vault places. For example if @@ -41,13 +233,103 @@ impl ::prost::Name for Params { "/dydxprotocol.vault.Params".into() } } +/// NumShares represents the number of shares. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NumShares { + /// Number of shares. + #[prost(bytes = "vec", tag = "2")] + pub num_shares: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for NumShares { + const NAME: &'static str = "NumShares"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.NumShares".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.NumShares".into() + } +} +/// OwnerShare is a type for owner shares. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OwnerShare { + #[prost(string, tag = "1")] + pub owner: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub shares: ::core::option::Option, +} +impl ::prost::Name for OwnerShare { + const NAME: &'static str = "OwnerShare"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.OwnerShare".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.OwnerShare".into() + } +} +/// OwnerShareUnlocks stores share unlocks for an owner. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OwnerShareUnlocks { + /// Address of the owner of below shares. + #[prost(string, tag = "1")] + pub owner_address: ::prost::alloc::string::String, + /// All share unlocks. + #[prost(message, repeated, tag = "2")] + pub share_unlocks: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for OwnerShareUnlocks { + const NAME: &'static str = "OwnerShareUnlocks"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.OwnerShareUnlocks".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.OwnerShareUnlocks".into() + } +} +/// ShareUnlock stores a single instance of `shares` number of shares +/// unlocking at block height `unlock_block_height`. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ShareUnlock { + /// Number of shares to unlock. + #[prost(message, optional, tag = "1")] + pub shares: ::core::option::Option, + /// Block height at which above shares unlock. + #[prost(uint32, tag = "2")] + pub unlock_block_height: u32, +} +impl ::prost::Name for ShareUnlock { + const NAME: &'static str = "ShareUnlock"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.ShareUnlock".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.ShareUnlock".into() + } +} /// GenesisState defines `x/vault`'s genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { - /// The parameters of the module. + /// The total number of shares, including any locked ones. #[prost(message, optional, tag = "1")] - pub params: ::core::option::Option, + pub total_shares: ::core::option::Option, + /// The shares of each owner, including any locked ones. + #[prost(message, repeated, tag = "2")] + pub owner_shares: ::prost::alloc::vec::Vec, + /// The vaults. + #[prost(message, repeated, tag = "3")] + pub vaults: ::prost::alloc::vec::Vec, + /// The default quoting parameters for all vaults. + #[prost(message, optional, tag = "4")] + pub default_quoting_params: ::core::option::Option, + /// All owner share unlocks. + #[prost(message, repeated, tag = "5")] + pub all_owner_share_unlocks: ::prost::alloc::vec::Vec, + /// The parameters regarding megavault operator. + #[prost(message, optional, tag = "6")] + pub operator_params: ::core::option::Option, } impl ::prost::Name for GenesisState { const NAME: &'static str = "GenesisState"; @@ -59,77 +341,82 @@ impl ::prost::Name for GenesisState { "/dydxprotocol.vault.GenesisState".into() } } -/// VaultId uniquely identifies a vault by its type and number. -#[allow(clippy::derive_partial_eq_without_eq)] +/// Vault defines the state of a vault. #[derive(Clone, PartialEq, ::prost::Message)] -pub struct VaultId { - /// Type of the vault. - #[prost(enumeration = "VaultType", tag = "1")] - pub r#type: i32, - /// Unique ID of the vault within above type. - #[prost(uint32, tag = "2")] - pub number: u32, +pub struct Vault { + /// The ID of the vault. + #[prost(message, optional, tag = "1")] + pub vault_id: ::core::option::Option, + /// The parameters of the vault. + #[prost(message, optional, tag = "2")] + pub vault_params: ::core::option::Option, + /// The client IDs of the most recently placed orders of the vault. + #[prost(uint32, repeated, tag = "3")] + pub most_recent_client_ids: ::prost::alloc::vec::Vec, } -impl ::prost::Name for VaultId { - const NAME: &'static str = "VaultId"; +impl ::prost::Name for Vault { + const NAME: &'static str = "Vault"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.VaultId".into() + "dydxprotocol.vault.Vault".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.VaultId".into() + "/dydxprotocol.vault.Vault".into() } } -/// NumShares represents the number of shares in a vault. -#[allow(clippy::derive_partial_eq_without_eq)] +/// GenesisStateV6 defines `x/vault`'s genesis state in v6.x. +/// Deprecated since v7.x in favor of GenesisState. #[derive(Clone, PartialEq, ::prost::Message)] -pub struct NumShares { - /// Number of shares. - #[prost(bytes = "vec", tag = "2")] - pub num_shares: ::prost::alloc::vec::Vec, +pub struct GenesisStateV6 { + /// The vaults. + #[prost(message, repeated, tag = "2")] + pub vaults: ::prost::alloc::vec::Vec, + /// The default quoting parameters for all vaults. + #[prost(message, optional, tag = "3")] + pub default_quoting_params: ::core::option::Option, } -impl ::prost::Name for NumShares { - const NAME: &'static str = "NumShares"; +impl ::prost::Name for GenesisStateV6 { + const NAME: &'static str = "GenesisStateV6"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.NumShares".into() + "dydxprotocol.vault.GenesisStateV6".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.NumShares".into() + "/dydxprotocol.vault.GenesisStateV6".into() } } -/// VaultType represents different types of vaults. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum VaultType { - /// Default value, invalid and unused. - Unspecified = 0, - /// Vault is associated with a CLOB pair. - Clob = 1, +/// VaultV6 defines the state of a vault. +/// Deprecated since v7.x in favor of Vault. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VaultV6 { + /// The ID of the vault. + #[prost(message, optional, tag = "1")] + pub vault_id: ::core::option::Option, + /// The total number of shares in the vault. + #[prost(message, optional, tag = "2")] + pub total_shares: ::core::option::Option, + /// The shares of each owner in the vault. + #[prost(message, repeated, tag = "3")] + pub owner_shares: ::prost::alloc::vec::Vec, + /// The parameters of the vault. + #[prost(message, optional, tag = "4")] + pub vault_params: ::core::option::Option, + /// The client IDs of the most recently placed orders of the vault. + #[prost(uint32, repeated, tag = "5")] + pub most_recent_client_ids: ::prost::alloc::vec::Vec, } -impl VaultType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - VaultType::Unspecified => "VAULT_TYPE_UNSPECIFIED", - VaultType::Clob => "VAULT_TYPE_CLOB", - } +impl ::prost::Name for VaultV6 { + const NAME: &'static str = "VaultV6"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.VaultV6".into() } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "VAULT_TYPE_UNSPECIFIED" => Some(Self::Unspecified), - "VAULT_TYPE_CLOB" => Some(Self::Clob), - _ => None, - } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.VaultV6".into() } } /// QueryParamsRequest is a request type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryParamsRequest {} impl ::prost::Name for QueryParamsRequest { const NAME: &'static str = "QueryParamsRequest"; @@ -142,11 +429,12 @@ impl ::prost::Name for QueryParamsRequest { } } /// QueryParamsResponse is a response type for the Params RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryParamsResponse { #[prost(message, optional, tag = "1")] - pub params: ::core::option::Option, + pub default_quoting_params: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub operator_params: ::core::option::Option, } impl ::prost::Name for QueryParamsResponse { const NAME: &'static str = "QueryParamsResponse"; @@ -159,8 +447,7 @@ impl ::prost::Name for QueryParamsResponse { } } /// QueryVaultRequest is a request type for the Vault RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QueryVaultRequest { #[prost(enumeration = "VaultType", tag = "1")] pub r#type: i32, @@ -178,19 +465,20 @@ impl ::prost::Name for QueryVaultRequest { } } /// QueryVaultResponse is a response type for the Vault RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryVaultResponse { #[prost(message, optional, tag = "1")] pub vault_id: ::core::option::Option, #[prost(message, optional, tag = "2")] pub subaccount_id: ::core::option::Option, - #[prost(uint64, tag = "3")] - pub equity: u64, - #[prost(uint64, tag = "4")] - pub inventory: u64, - #[prost(uint64, tag = "5")] - pub total_shares: u64, + #[prost(bytes = "vec", tag = "3")] + pub equity: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "4")] + pub inventory: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "5")] + pub vault_params: ::core::option::Option, + #[prost(uint32, repeated, tag = "6")] + pub most_recent_client_ids: ::prost::alloc::vec::Vec, } impl ::prost::Name for QueryVaultResponse { const NAME: &'static str = "QueryVaultResponse"; @@ -203,7 +491,6 @@ impl ::prost::Name for QueryVaultResponse { } } /// QueryAllVaultsRequest is a request type for the AllVaults RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryAllVaultsRequest { #[prost(message, optional, tag = "1")] @@ -211,111 +498,897 @@ pub struct QueryAllVaultsRequest { super::super::cosmos::base::query::v1beta1::PageRequest, >, } -impl ::prost::Name for QueryAllVaultsRequest { - const NAME: &'static str = "QueryAllVaultsRequest"; +impl ::prost::Name for QueryAllVaultsRequest { + const NAME: &'static str = "QueryAllVaultsRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryAllVaultsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryAllVaultsRequest".into() + } +} +/// QueryAllVaultsResponse is a response type for the AllVaults RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryAllVaultsResponse { + #[prost(message, repeated, tag = "1")] + pub vaults: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryAllVaultsResponse { + const NAME: &'static str = "QueryAllVaultsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryAllVaultsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryAllVaultsResponse".into() + } +} +/// QueryMegavaultTotalSharesRequest is a request type for the +/// MegavaultTotalShares RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryMegavaultTotalSharesRequest {} +impl ::prost::Name for QueryMegavaultTotalSharesRequest { + const NAME: &'static str = "QueryMegavaultTotalSharesRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultTotalSharesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultTotalSharesRequest".into() + } +} +/// QueryMegavaultTotalSharesResponse is a response type for the +/// MegavaultTotalShares RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultTotalSharesResponse { + #[prost(message, optional, tag = "1")] + pub total_shares: ::core::option::Option, +} +impl ::prost::Name for QueryMegavaultTotalSharesResponse { + const NAME: &'static str = "QueryMegavaultTotalSharesResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultTotalSharesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultTotalSharesResponse".into() + } +} +/// QueryMegavaultOwnerSharesRequest is a request type for the +/// MegavaultOwnerShares RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultOwnerSharesRequest { + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +impl ::prost::Name for QueryMegavaultOwnerSharesRequest { + const NAME: &'static str = "QueryMegavaultOwnerSharesRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultOwnerSharesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultOwnerSharesRequest".into() + } +} +/// QueryMegavaultOwnerSharesResponse is a response type for the +/// MegavaultOwnerShares RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultOwnerSharesResponse { + /// Owner address. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// Total number of shares that belong to the owner. + #[prost(message, optional, tag = "2")] + pub shares: ::core::option::Option, + /// All share unlocks. + #[prost(message, repeated, tag = "3")] + pub share_unlocks: ::prost::alloc::vec::Vec, + /// Owner equity in megavault (in quote quantums). + #[prost(bytes = "vec", tag = "4")] + pub equity: ::prost::alloc::vec::Vec, + /// Equity that owner can withdraw in quote quantums (as one cannot + /// withdraw locked shares). + #[prost(bytes = "vec", tag = "5")] + pub withdrawable_equity: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for QueryMegavaultOwnerSharesResponse { + const NAME: &'static str = "QueryMegavaultOwnerSharesResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultOwnerSharesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultOwnerSharesResponse".into() + } +} +/// QueryMegavaultAllOwnerSharesRequest is a request type for the +/// MegavaultAllOwnerShares RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultAllOwnerSharesRequest { + #[prost(message, optional, tag = "1")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageRequest, + >, +} +impl ::prost::Name for QueryMegavaultAllOwnerSharesRequest { + const NAME: &'static str = "QueryMegavaultAllOwnerSharesRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultAllOwnerSharesRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultAllOwnerSharesRequest".into() + } +} +/// QueryMegavaultAllOwnerSharesResponse is a response type for the +/// MegavaultAllOwnerShares RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultAllOwnerSharesResponse { + #[prost(message, repeated, tag = "1")] + pub owner_shares: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pagination: ::core::option::Option< + super::super::cosmos::base::query::v1beta1::PageResponse, + >, +} +impl ::prost::Name for QueryMegavaultAllOwnerSharesResponse { + const NAME: &'static str = "QueryMegavaultAllOwnerSharesResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultAllOwnerSharesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultAllOwnerSharesResponse".into() + } +} +/// QueryVaultParamsRequest is a request for the VaultParams RPC method. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct QueryVaultParamsRequest { + #[prost(enumeration = "VaultType", tag = "1")] + pub r#type: i32, + #[prost(uint32, tag = "2")] + pub number: u32, +} +impl ::prost::Name for QueryVaultParamsRequest { + const NAME: &'static str = "QueryVaultParamsRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryVaultParamsRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryVaultParamsRequest".into() + } +} +/// QueryVaultParamsResponse is a response for the VaultParams RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryVaultParamsResponse { + #[prost(message, optional, tag = "1")] + pub vault_id: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub vault_params: ::core::option::Option, +} +impl ::prost::Name for QueryVaultParamsResponse { + const NAME: &'static str = "QueryVaultParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryVaultParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryVaultParamsResponse".into() + } +} +/// QueryMegavaultWithdrawalInfoRequest is a request type for the +/// MegavaultWithdrawalInfo RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultWithdrawalInfoRequest { + /// Number of shares to withdraw. + #[prost(message, optional, tag = "1")] + pub shares_to_withdraw: ::core::option::Option, +} +impl ::prost::Name for QueryMegavaultWithdrawalInfoRequest { + const NAME: &'static str = "QueryMegavaultWithdrawalInfoRequest"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultWithdrawalInfoRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultWithdrawalInfoRequest".into() + } +} +/// QueryMegavaultWithdrawalInfoResponse is a response type for the +/// MegavaultWithdrawalInfo RPC method. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryMegavaultWithdrawalInfoResponse { + /// Number of shares to withdraw. + #[prost(message, optional, tag = "1")] + pub shares_to_withdraw: ::core::option::Option, + /// Number of quote quantums above `shares` are expected to redeem. + /// Withdrawl slippage can be calculated by comparing + /// `expected_quote_quantums` with + /// `megavault_equity * shares_to_withdraw / total_shares` + #[prost(bytes = "vec", tag = "2")] + pub expected_quote_quantums: ::prost::alloc::vec::Vec, + /// Equity of megavault (in quote quantums). + #[prost(bytes = "vec", tag = "3")] + pub megavault_equity: ::prost::alloc::vec::Vec, + /// Total shares in megavault. + #[prost(message, optional, tag = "4")] + pub total_shares: ::core::option::Option, +} +impl ::prost::Name for QueryMegavaultWithdrawalInfoResponse { + const NAME: &'static str = "QueryMegavaultWithdrawalInfoResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.QueryMegavaultWithdrawalInfoResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.QueryMegavaultWithdrawalInfoResponse".into() + } +} +/// Generated client implementations. +pub mod query_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Query defines the gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + #[cfg(feature = "grpc-transport")] + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Queries the Params. + pub async fn params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/Params", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Params")); + self.inner.unary(req, path, codec).await + } + /// Queries a Vault by type and number. + pub async fn vault( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/Vault", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Vault")); + self.inner.unary(req, path, codec).await + } + /// Queries all vaults. + pub async fn all_vaults( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/AllVaults", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "AllVaults")); + self.inner.unary(req, path, codec).await + } + /// Queries total shares of megavault. + pub async fn megavault_total_shares( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/MegavaultTotalShares", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.vault.Query", "MegavaultTotalShares"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries owner shares of megavault. + pub async fn megavault_owner_shares( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/MegavaultOwnerShares", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("dydxprotocol.vault.Query", "MegavaultOwnerShares"), + ); + self.inner.unary(req, path, codec).await + } + /// Queries all owner shares of megavault. + pub async fn megavault_all_owner_shares( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/MegavaultAllOwnerShares", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.vault.Query", + "MegavaultAllOwnerShares", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Queries vault params of a vault. + pub async fn vault_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/VaultParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Query", "VaultParams")); + self.inner.unary(req, path, codec).await + } + /// Queries withdrawal info for megavault. + pub async fn megavault_withdrawal_info( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Query/MegavaultWithdrawalInfo", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "dydxprotocol.vault.Query", + "MegavaultWithdrawalInfo", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// MsgDepositToMegavault deposits the specified asset from the subaccount to +/// megavault. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToMegavault { + /// The subaccount to deposit from. + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// Number of quote quantums to deposit. + #[prost(bytes = "vec", tag = "2")] + pub quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgDepositToMegavault { + const NAME: &'static str = "MsgDepositToMegavault"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgDepositToMegavault".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgDepositToMegavault".into() + } +} +/// MsgDepositToMegavaultResponse is the Msg/DepositToMegavault response type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgDepositToMegavaultResponse { + /// The number of shares minted from the deposit. + #[prost(message, optional, tag = "1")] + pub minted_shares: ::core::option::Option, +} +impl ::prost::Name for MsgDepositToMegavaultResponse { + const NAME: &'static str = "MsgDepositToMegavaultResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgDepositToMegavaultResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgDepositToMegavaultResponse".into() + } +} +/// MsgWithdrawFromMegavault withdraws the specified shares from megavault to +/// a subaccount. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgWithdrawFromMegavault { + /// The subaccount to withdraw to. + #[prost(message, optional, tag = "1")] + pub subaccount_id: ::core::option::Option, + /// Number of shares to withdraw. + #[prost(message, optional, tag = "2")] + pub shares: ::core::option::Option, + /// The minimum number of quote quantums above shares should redeem, i.e. + /// transaction fails if above shares redeem less than min_quote_quantums. + #[prost(bytes = "vec", tag = "3")] + pub min_quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgWithdrawFromMegavault { + const NAME: &'static str = "MsgWithdrawFromMegavault"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgWithdrawFromMegavault".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgWithdrawFromMegavault".into() + } +} +/// MsgWithdrawFromMegavaultResponse is the Msg/WithdrawFromMegavault response +/// type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgWithdrawFromMegavaultResponse { + /// The number of quote quantums redeemed from the withdrawal. + #[prost(bytes = "vec", tag = "1")] + pub quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgWithdrawFromMegavaultResponse { + const NAME: &'static str = "MsgWithdrawFromMegavaultResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgWithdrawFromMegavaultResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse".into() + } +} +/// MsgUpdateDefaultQuotingParams is the Msg/UpdateDefaultQuotingParams request +/// type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateDefaultQuotingParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The quoting parameters to update to. Every field must be set. + #[prost(message, optional, tag = "2")] + pub default_quoting_params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateDefaultQuotingParams { + const NAME: &'static str = "MsgUpdateDefaultQuotingParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateDefaultQuotingParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateDefaultQuotingParams".into() + } +} +/// MsgUpdateDefaultQuotingParamsResponse is the Msg/UpdateDefaultQuotingParams +/// response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgUpdateDefaultQuotingParamsResponse {} +impl ::prost::Name for MsgUpdateDefaultQuotingParamsResponse { + const NAME: &'static str = "MsgUpdateDefaultQuotingParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateDefaultQuotingParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateDefaultQuotingParamsResponse".into() + } +} +/// MsgSetVaultParams is the Msg/SetVaultParams request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSetVaultParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vault to set params of. + #[prost(message, optional, tag = "2")] + pub vault_id: ::core::option::Option, + /// The parameters to set. + #[prost(message, optional, tag = "3")] + pub vault_params: ::core::option::Option, +} +impl ::prost::Name for MsgSetVaultParams { + const NAME: &'static str = "MsgSetVaultParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgSetVaultParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgSetVaultParams".into() + } +} +/// MsgSetVaultParamsResponse is the Msg/SetVaultParams response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgSetVaultParamsResponse {} +impl ::prost::Name for MsgSetVaultParamsResponse { + const NAME: &'static str = "MsgSetVaultParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgSetVaultParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgSetVaultParamsResponse".into() + } +} +/// MsgUnlockShares is the Msg/UnlockShares request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUnlockShares { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Address of the owner to unlock shares of. + #[prost(string, tag = "2")] + pub owner_address: ::prost::alloc::string::String, +} +impl ::prost::Name for MsgUnlockShares { + const NAME: &'static str = "MsgUnlockShares"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUnlockShares".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUnlockShares".into() + } +} +/// MsgUnlockSharesResponse is the Msg/UnlockShares response type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUnlockSharesResponse { + /// The number of shares unlocked. + #[prost(message, optional, tag = "1")] + pub unlocked_shares: ::core::option::Option, +} +impl ::prost::Name for MsgUnlockSharesResponse { + const NAME: &'static str = "MsgUnlockSharesResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUnlockSharesResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUnlockSharesResponse".into() + } +} +/// MsgUpdateOperatorParams is the Msg/UpdateOperatorParams request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgUpdateOperatorParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// Operator parameters to set. + #[prost(message, optional, tag = "2")] + pub params: ::core::option::Option, +} +impl ::prost::Name for MsgUpdateOperatorParams { + const NAME: &'static str = "MsgUpdateOperatorParams"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateOperatorParams".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateOperatorParams".into() + } +} +/// MsgUpdateVaultParamsResponse is the Msg/UpdateOperatorParams response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgUpdateOperatorParamsResponse {} +impl ::prost::Name for MsgUpdateOperatorParamsResponse { + const NAME: &'static str = "MsgUpdateOperatorParamsResponse"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgUpdateOperatorParamsResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgUpdateOperatorParamsResponse".into() + } +} +/// MsgAllocateToVault is the Msg/AllocateToVault request type. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgAllocateToVault { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vault to allocate to. + #[prost(message, optional, tag = "2")] + pub vault_id: ::core::option::Option, + /// Number of quote quantums to allocate. + #[prost(bytes = "vec", tag = "3")] + pub quote_quantums: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for MsgAllocateToVault { + const NAME: &'static str = "MsgAllocateToVault"; + const PACKAGE: &'static str = "dydxprotocol.vault"; + fn full_name() -> ::prost::alloc::string::String { + "dydxprotocol.vault.MsgAllocateToVault".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/dydxprotocol.vault.MsgAllocateToVault".into() + } +} +/// MsgAllocateToVaultResponse is the Msg/AllocateToVault response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgAllocateToVaultResponse {} +impl ::prost::Name for MsgAllocateToVaultResponse { + const NAME: &'static str = "MsgAllocateToVaultResponse"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.QueryAllVaultsRequest".into() + "dydxprotocol.vault.MsgAllocateToVaultResponse".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.QueryAllVaultsRequest".into() + "/dydxprotocol.vault.MsgAllocateToVaultResponse".into() } } -/// QueryAllVaultsResponse is a response type for the AllVaults RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] +/// MsgRetrieveFromVault is the Msg/RetrieveFromVault request type. #[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryAllVaultsResponse { - #[prost(message, repeated, tag = "1")] - pub vaults: ::prost::alloc::vec::Vec, +pub struct MsgRetrieveFromVault { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vault to retrieve from. #[prost(message, optional, tag = "2")] - pub pagination: ::core::option::Option< - super::super::cosmos::base::query::v1beta1::PageResponse, - >, + pub vault_id: ::core::option::Option, + /// Number of quote quantums to retrieve. + #[prost(bytes = "vec", tag = "3")] + pub quote_quantums: ::prost::alloc::vec::Vec, } -impl ::prost::Name for QueryAllVaultsResponse { - const NAME: &'static str = "QueryAllVaultsResponse"; +impl ::prost::Name for MsgRetrieveFromVault { + const NAME: &'static str = "MsgRetrieveFromVault"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.QueryAllVaultsResponse".into() + "dydxprotocol.vault.MsgRetrieveFromVault".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.QueryAllVaultsResponse".into() + "/dydxprotocol.vault.MsgRetrieveFromVault".into() } } -/// QueryOwnerSharesRequest is a request type for the OwnerShares RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryOwnerSharesRequest { - #[prost(enumeration = "VaultType", tag = "1")] - pub r#type: i32, - #[prost(uint32, tag = "2")] - pub number: u32, - #[prost(message, optional, tag = "3")] - pub pagination: ::core::option::Option< - super::super::cosmos::base::query::v1beta1::PageRequest, - >, -} -impl ::prost::Name for QueryOwnerSharesRequest { - const NAME: &'static str = "QueryOwnerSharesRequest"; +/// MsgRetrieveFromVaultResponse is the Msg/RetrieveFromVault response type. +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MsgRetrieveFromVaultResponse {} +impl ::prost::Name for MsgRetrieveFromVaultResponse { + const NAME: &'static str = "MsgRetrieveFromVaultResponse"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.QueryOwnerSharesRequest".into() + "dydxprotocol.vault.MsgRetrieveFromVaultResponse".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.QueryOwnerSharesRequest".into() + "/dydxprotocol.vault.MsgRetrieveFromVaultResponse".into() } } -/// OwnerShare is a type for owner shares in a vault. -#[allow(clippy::derive_partial_eq_without_eq)] +/// MsgUpdateParams is the Msg/UpdateParams request type. +/// Deprecated since v6.x as is replaced by MsgUpdateDefaultQuotingParams. #[derive(Clone, PartialEq, ::prost::Message)] -pub struct OwnerShare { +pub struct MsgUpdateParams { #[prost(string, tag = "1")] - pub owner: ::prost::alloc::string::String, + pub authority: ::prost::alloc::string::String, + /// The parameters to update. Each field must be set. #[prost(message, optional, tag = "2")] - pub shares: ::core::option::Option, + pub params: ::core::option::Option, } -impl ::prost::Name for OwnerShare { - const NAME: &'static str = "OwnerShare"; +impl ::prost::Name for MsgUpdateParams { + const NAME: &'static str = "MsgUpdateParams"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.OwnerShare".into() + "dydxprotocol.vault.MsgUpdateParams".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.OwnerShare".into() + "/dydxprotocol.vault.MsgUpdateParams".into() } } -/// QueryOwnerSharesResponse is a response type for the OwnerShares RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] +/// MsgSetVaultQuotingParams is the Msg/SetVaultQuotingParams request type. +/// Deprecated since v6.x as is replaced by MsgSetVaultParams. #[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryOwnerSharesResponse { - #[prost(message, repeated, tag = "1")] - pub owner_shares: ::prost::alloc::vec::Vec, +pub struct MsgSetVaultQuotingParams { + #[prost(string, tag = "1")] + pub authority: ::prost::alloc::string::String, + /// The vault to set quoting params of. #[prost(message, optional, tag = "2")] - pub pagination: ::core::option::Option< - super::super::cosmos::base::query::v1beta1::PageResponse, - >, + pub vault_id: ::core::option::Option, + /// The quoting parameters to set. Each field must be set. + #[prost(message, optional, tag = "3")] + pub quoting_params: ::core::option::Option, } -impl ::prost::Name for QueryOwnerSharesResponse { - const NAME: &'static str = "QueryOwnerSharesResponse"; +impl ::prost::Name for MsgSetVaultQuotingParams { + const NAME: &'static str = "MsgSetVaultQuotingParams"; const PACKAGE: &'static str = "dydxprotocol.vault"; fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.QueryOwnerSharesResponse".into() + "dydxprotocol.vault.MsgSetVaultQuotingParams".into() } fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.QueryOwnerSharesResponse".into() + "/dydxprotocol.vault.MsgSetVaultQuotingParams".into() } } /// Generated client implementations. -pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] +pub mod msg_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; - /// Query defines the gRPC querier service. + /// Msg defines the Msg service. #[derive(Debug, Clone)] - pub struct QueryClient { + pub struct MsgClient { inner: tonic::client::Grpc, } - impl QueryClient { + #[cfg(feature = "grpc-transport")] + impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result where @@ -326,12 +1399,12 @@ pub mod query_client { Ok(Self::new(conn)) } } - impl QueryClient + impl MsgClient where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -344,7 +1417,7 @@ pub mod query_client { pub fn with_interceptor( inner: T, interceptor: F, - ) -> QueryClient> + ) -> MsgClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, @@ -356,9 +1429,9 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { - QueryClient::new(InterceptedService::new(inner, interceptor)) + MsgClient::new(InterceptedService::new(inner, interceptor)) } /// Compress requests with the given encoding. /// @@ -391,320 +1464,214 @@ pub mod query_client { self.inner = self.inner.max_encoding_message_size(limit); self } - /// Queries the Params. - pub async fn params( + /// DepositToMegavault deposits funds into megavault. + pub async fn deposit_to_megavault( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Query/Params", + "/dydxprotocol.vault.Msg/DepositToMegavault", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Params")); + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "DepositToMegavault")); self.inner.unary(req, path, codec).await } - /// Queries a Vault by type and number. - pub async fn vault( + /// WithdrawFromMegavault withdraws shares from megavault. + pub async fn withdraw_from_megavault( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Query/Vault", + "/dydxprotocol.vault.Msg/WithdrawFromMegavault", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Query", "Vault")); + .insert( + GrpcMethod::new("dydxprotocol.vault.Msg", "WithdrawFromMegavault"), + ); self.inner.unary(req, path, codec).await } - /// Queries all vaults. - pub async fn all_vaults( + /// UpdateDefaultQuotingParams updates the default quoting params in state. + pub async fn update_default_quoting_params( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Query/AllVaults", + "/dydxprotocol.vault.Msg/UpdateDefaultQuotingParams", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Query", "AllVaults")); + .insert( + GrpcMethod::new( + "dydxprotocol.vault.Msg", + "UpdateDefaultQuotingParams", + ), + ); self.inner.unary(req, path, codec).await } - /// Queries owner shares of a vault. - pub async fn owner_shares( + /// UpdateOperatorParams sets the parameters regarding megavault operator. + pub async fn update_operator_params( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Query/OwnerShares", + "/dydxprotocol.vault.Msg/UpdateOperatorParams", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Query", "OwnerShares")); + .insert( + GrpcMethod::new("dydxprotocol.vault.Msg", "UpdateOperatorParams"), + ); self.inner.unary(req, path, codec).await } - } -} -/// MsgDepositToVault is the Msg/DepositToVault request type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgDepositToVault { - /// The vault to deposit into. - #[prost(message, optional, tag = "1")] - pub vault_id: ::core::option::Option, - /// The subaccount to deposit from. - #[prost(message, optional, tag = "2")] - pub subaccount_id: ::core::option::Option, - /// Number of quote quantums to deposit. - #[prost(bytes = "vec", tag = "3")] - pub quote_quantums: ::prost::alloc::vec::Vec, -} -impl ::prost::Name for MsgDepositToVault { - const NAME: &'static str = "MsgDepositToVault"; - const PACKAGE: &'static str = "dydxprotocol.vault"; - fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.MsgDepositToVault".into() - } - fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.MsgDepositToVault".into() - } -} -/// MsgDepositToVaultResponse is the Msg/DepositToVault response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgDepositToVaultResponse {} -impl ::prost::Name for MsgDepositToVaultResponse { - const NAME: &'static str = "MsgDepositToVaultResponse"; - const PACKAGE: &'static str = "dydxprotocol.vault"; - fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.MsgDepositToVaultResponse".into() - } - fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.MsgDepositToVaultResponse".into() - } -} -/// MsgUpdateParams is the Msg/UpdateParams request type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgUpdateParams { - #[prost(string, tag = "1")] - pub authority: ::prost::alloc::string::String, - /// The parameters to update. Each field must be set. - #[prost(message, optional, tag = "2")] - pub params: ::core::option::Option, -} -impl ::prost::Name for MsgUpdateParams { - const NAME: &'static str = "MsgUpdateParams"; - const PACKAGE: &'static str = "dydxprotocol.vault"; - fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.MsgUpdateParams".into() - } - fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.MsgUpdateParams".into() - } -} -/// MsgUpdateParamsResponse is the Msg/UpdateParams response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgUpdateParamsResponse {} -impl ::prost::Name for MsgUpdateParamsResponse { - const NAME: &'static str = "MsgUpdateParamsResponse"; - const PACKAGE: &'static str = "dydxprotocol.vault"; - fn full_name() -> ::prost::alloc::string::String { - "dydxprotocol.vault.MsgUpdateParamsResponse".into() - } - fn type_url() -> ::prost::alloc::string::String { - "/dydxprotocol.vault.MsgUpdateParamsResponse".into() - } -} -/// Generated client implementations. -pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// Msg defines the Msg service. - #[derive(Debug, Clone)] - pub struct MsgClient { - inner: tonic::client::Grpc, - } - impl MsgClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl MsgClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> MsgClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + Send + Sync, - { - MsgClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self + /// SetVaultParams sets the parameters of a specific vault. + pub async fn set_vault_params( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Msg/SetVaultParams", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "SetVaultParams")); + self.inner.unary(req, path, codec).await } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self + /// UnlockShares unlocks an owner's shares that are due to unlock by the block + /// height that this transaction is included in. + pub async fn unlock_shares( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/dydxprotocol.vault.Msg/UnlockShares", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "UnlockShares")); + self.inner.unary(req, path, codec).await } - /// DepositToVault deposits funds into a vault. - pub async fn deposit_to_vault( + /// AllocateToVault allocates funds from main vault to a vault. + pub async fn allocate_to_vault( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Msg/DepositToVault", + "/dydxprotocol.vault.Msg/AllocateToVault", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "DepositToVault")); + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "AllocateToVault")); self.inner.unary(req, path, codec).await } - /// UpdateParams updates the Params in state. - pub async fn update_params( + /// RetrieveFromVault retrieves funds from a vault to main vault. + pub async fn retrieve_from_vault( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/dydxprotocol.vault.Msg/UpdateParams", + "/dydxprotocol.vault.Msg/RetrieveFromVault", ); let mut req = request.into_request(); req.extensions_mut() - .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "UpdateParams")); + .insert(GrpcMethod::new("dydxprotocol.vault.Msg", "RetrieveFromVault")); self.inner.unary(req, path, codec).await } } diff --git a/v4-proto-rs/src/dydxprotocol.vest.rs b/v4-proto-rs/src/dydxprotocol.vest.rs index f875d24e7d..34aeb77068 100644 --- a/v4-proto-rs/src/dydxprotocol.vest.rs +++ b/v4-proto-rs/src/dydxprotocol.vest.rs @@ -1,7 +1,6 @@ // This file is @generated by prost-build. /// VestEntry specifies a Vester Account and the rate at which tokens are /// dripped into the corresponding Treasury Account. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VestEntry { /// The module account to vest tokens from. @@ -33,7 +32,6 @@ impl ::prost::Name for VestEntry { } } /// GenesisState defines the vest module's genesis state. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { /// The vest entries at genesis. @@ -51,7 +49,6 @@ impl ::prost::Name for GenesisState { } } /// QueryVestEntryRequest is a request type for the VestEntry RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryVestEntryRequest { #[prost(string, tag = "1")] @@ -68,7 +65,6 @@ impl ::prost::Name for QueryVestEntryRequest { } } /// QueryVestEntryResponse is a response type for the VestEntry RPC method. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryVestEntryResponse { #[prost(message, optional, tag = "1")] @@ -86,7 +82,13 @@ impl ::prost::Name for QueryVestEntryResponse { } /// Generated client implementations. pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Query defines the gRPC querier service. @@ -94,6 +96,7 @@ pub mod query_client { pub struct QueryClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl QueryClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -109,8 +112,8 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -135,7 +138,7 @@ pub mod query_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { QueryClient::new(InterceptedService::new(inner, interceptor)) } @@ -182,8 +185,7 @@ pub mod query_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -199,7 +201,6 @@ pub mod query_client { } } /// MsgDeleteVestEntry is the Msg/DeleteVestEntry request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgDeleteVestEntry { /// authority is the address that controls the module. @@ -220,8 +221,7 @@ impl ::prost::Name for MsgDeleteVestEntry { } } /// MsgDeleteVestEntryResponse is the Msg/DeleteVestEntry response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgDeleteVestEntryResponse {} impl ::prost::Name for MsgDeleteVestEntryResponse { const NAME: &'static str = "MsgDeleteVestEntryResponse"; @@ -234,7 +234,6 @@ impl ::prost::Name for MsgDeleteVestEntryResponse { } } /// MsgSetVestEntry is the Msg/SetVestEntry request type. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSetVestEntry { /// authority is the address that controls the module. @@ -255,8 +254,7 @@ impl ::prost::Name for MsgSetVestEntry { } } /// MsgSetVestEntryResponse is the Msg/SetVestEntry response type. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct MsgSetVestEntryResponse {} impl ::prost::Name for MsgSetVestEntryResponse { const NAME: &'static str = "MsgSetVestEntryResponse"; @@ -270,7 +268,13 @@ impl ::prost::Name for MsgSetVestEntryResponse { } /// Generated client implementations. pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; use tonic::codegen::http::Uri; /// Msg defines the Msg service. @@ -278,6 +282,7 @@ pub mod msg_client { pub struct MsgClient { inner: tonic::client::Grpc, } + #[cfg(feature = "grpc-transport")] impl MsgClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result @@ -293,8 +298,8 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, { pub fn new(inner: T) -> Self { let inner = tonic::client::Grpc::new(inner); @@ -319,7 +324,7 @@ pub mod msg_client { >, , - >>::Error: Into + Send + Sync, + >>::Error: Into + std::marker::Send + std::marker::Sync, { MsgClient::new(InterceptedService::new(inner, interceptor)) } @@ -366,8 +371,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; @@ -392,8 +396,7 @@ pub mod msg_client { .ready() .await .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, + tonic::Status::unknown( format!("Service was not ready: {}", e.into()), ) })?; diff --git a/v4-proto-rs/src/google.api.rs b/v4-proto-rs/src/google.api.rs index 08318f49cf..89bf932b4f 100644 --- a/v4-proto-rs/src/google.api.rs +++ b/v4-proto-rs/src/google.api.rs @@ -2,7 +2,6 @@ /// Defines the HTTP configuration for an API service. It contains a list of /// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method /// to one or more HTTP REST API methods. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Http { /// A list of HTTP configuration rules that apply to individual API methods. @@ -301,7 +300,6 @@ impl ::prost::Name for Http { /// If an API needs to use a JSON array for request or response body, it can map /// the request or response body to a repeated field. However, some gRPC /// Transcoding implementations may not support this feature. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct HttpRule { /// Selects a method to which this rule applies. @@ -342,7 +340,6 @@ pub mod http_rule { /// Determines the URL pattern is matched by this rules. This pattern can be /// used with any of the {get|put|post|delete|patch} methods. A custom method /// can be defined using the 'custom' field. - #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Pattern { /// Maps to HTTP GET. Used for listing and getting information about @@ -380,7 +377,6 @@ impl ::prost::Name for HttpRule { } } /// A custom pattern is used for defining custom HTTP verb. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CustomHttpPattern { /// The name of this custom HTTP verb. diff --git a/v4-proto-rs/src/lib.rs b/v4-proto-rs/src/lib.rs index 0e372c984a..3e97ff72e1 100644 --- a/v4-proto-rs/src/lib.rs +++ b/v4-proto-rs/src/lib.rs @@ -3,14 +3,15 @@ pub use cosmos_sdk_proto; include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/_includes.rs")); +use cosmos_sdk_proto::Any; use prost::Name; pub trait ToAny: Name + Sized { /// Converts the type to `prost_types::Any`. - fn to_any(self) -> prost_types::Any { + fn to_any(self) -> Any { let value = self.encode_to_vec(); let type_url = Self::type_url(); - prost_types::Any { type_url, value } + Any { type_url, value } } } @@ -23,8 +24,8 @@ mod test { use crate::dydxprotocol::clob::MsgCancelOrder; #[test] + /// Tests the conversion of `MsgCancelOrder` to `cosmos_sdk_proto::Any`. pub fn test_any_conversion() { - /// Tests the conversion of `MsgCancelOrder` to `prost_types::Any`. let msg = MsgCancelOrder { order_id: None, good_til_oneof: None, @@ -35,8 +36,8 @@ mod test { } #[test] + /// Tests the conversion of `MsgSend` to `cosmos_sdk_proto::Any`. pub fn test_any_conversion_wrapped() { - /// Tests the conversion of `MsgSend` to `prost_types::Any`. let msg = MsgSend::default(); let any = msg.to_any(); let url = "/cosmos.bank.v1beta1.MsgSend"; From a65976ec5ce6e684b4188f2b434a9cc9018d6826 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Thu, 14 Nov 2024 16:25:13 -0500 Subject: [PATCH 109/120] fix(affiliates): [OTE-898] Refactor subaccount username generation (#2569) --- .../postgres/__tests__/helpers/constants.ts | 15 + .../__tests__/helpers/mock-generators.ts | 9 + .../stores/subaccount-usernames-table.test.ts | 9 +- .../src/stores/subaccount-usernames-table.ts | 14 +- .../src/types/subaccount-usernames-types.ts | 1 + indexer/pnpm-lock.yaml | 12 + .../api/v4/affiliates-controller.ts | 12 +- .../helpers/usernames-helper.test.ts | 48 +- .../subaccount-username-generator.test.ts | 1 + indexer/services/roundtable/package.json | 2 + indexer/services/roundtable/src/config.ts | 5 +- .../roundtable/src/helpers/adjectives.json | 96 ++-- .../roundtable/src/helpers/nouns.json | 430 ++++++++++++++++-- .../src/helpers/usernames-helper.ts | 15 +- indexer/services/roundtable/src/index.ts | 1 + .../tasks/subaccount-username-generator.ts | 83 +++- 16 files changed, 625 insertions(+), 128 deletions(-) diff --git a/indexer/packages/postgres/__tests__/helpers/constants.ts b/indexer/packages/postgres/__tests__/helpers/constants.ts index 5de24209bd..1de37ba7ac 100644 --- a/indexer/packages/postgres/__tests__/helpers/constants.ts +++ b/indexer/packages/postgres/__tests__/helpers/constants.ts @@ -71,6 +71,7 @@ export const invalidTicker: string = 'INVALID-INVALID'; export const dydxChain: string = 'dydx'; export const defaultAddress: string = 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf'; export const defaultAddress2: string = 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf'; +export const defaultAddress3: string = 'dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4'; export const blockedAddress: string = 'dydx1f9k5qldwmqrnwy8hcgp4fw6heuvszt35egvtx2'; // Vault address for vault id 0 was generated using // script protocol/scripts/vault/get_vault.go @@ -100,6 +101,20 @@ export const defaultSubaccount3: SubaccountCreateObject = { updatedAtHeight: createdHeight, }; +export const defaultSubaccount2Num0: SubaccountCreateObject = { + address: defaultAddress2, + subaccountNumber: 0, + updatedAt: createdDateTime.toISO(), + updatedAtHeight: createdHeight, +}; + +export const defaultSubaccount3Num0: SubaccountCreateObject = { + address: defaultAddress3, + subaccountNumber: 0, + updatedAt: createdDateTime.toISO(), + updatedAtHeight: createdHeight, +}; + // defaultWalletAddress belongs to defaultWallet2 and is different from defaultAddress export const defaultSubaccountDefaultWalletAddress: SubaccountCreateObject = { address: defaultWalletAddress, diff --git a/indexer/packages/postgres/__tests__/helpers/mock-generators.ts b/indexer/packages/postgres/__tests__/helpers/mock-generators.ts index 34d9ada9e2..ea785b2944 100644 --- a/indexer/packages/postgres/__tests__/helpers/mock-generators.ts +++ b/indexer/packages/postgres/__tests__/helpers/mock-generators.ts @@ -35,8 +35,17 @@ import { isolatedPerpetualMarket2, isolatedSubaccount, isolatedSubaccount2, + defaultSubaccount2Num0, + defaultSubaccount3Num0, } from './constants'; +export async function seedAdditionalSubaccounts() { + await Promise.all([ + SubaccountTable.create(defaultSubaccount2Num0), + SubaccountTable.create(defaultSubaccount3Num0), + ]); +} + export async function seedData() { await Promise.all([ SubaccountTable.create(defaultSubaccount), diff --git a/indexer/packages/postgres/__tests__/stores/subaccount-usernames-table.test.ts b/indexer/packages/postgres/__tests__/stores/subaccount-usernames-table.test.ts index c069df9f59..71db35e943 100644 --- a/indexer/packages/postgres/__tests__/stores/subaccount-usernames-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/subaccount-usernames-table.test.ts @@ -6,17 +6,17 @@ import { clearData, migrate, teardown } from '../../src/helpers/db-helpers'; import { defaultSubaccountUsername, defaultSubaccountUsername2, - defaultSubaccountWithAlternateAddress, defaultWallet, defaultWallet2, duplicatedSubaccountUsername, subaccountUsernameWithAlternativeAddress, } from '../helpers/constants'; -import { seedData } from '../helpers/mock-generators'; +import { seedData, seedAdditionalSubaccounts } from '../helpers/mock-generators'; describe('SubaccountUsernames store', () => { beforeEach(async () => { await seedData(); + await seedAdditionalSubaccounts(); }); beforeAll(async () => { @@ -82,18 +82,17 @@ describe('SubaccountUsernames store', () => { const subaccountLength = subaccounts.length; await SubaccountUsernamesTable.create(defaultSubaccountUsername); const subaccountIds: SubaccountsWithoutUsernamesResult[] = await - SubaccountUsernamesTable.getSubaccountsWithoutUsernames(); + SubaccountUsernamesTable.getSubaccountZerosWithoutUsernames(1000); expect(subaccountIds.length).toEqual(subaccountLength - 1); }); it('Get username using address', async () => { await Promise.all([ - // Add two usernames for defaultWallet + // Add username for defaultWallet SubaccountUsernamesTable.create(defaultSubaccountUsername), SubaccountUsernamesTable.create(defaultSubaccountUsername2), // Add one username for alternativeWallet WalletTable.create(defaultWallet2), - SubaccountsTable.create(defaultSubaccountWithAlternateAddress), SubaccountUsernamesTable.create(subaccountUsernameWithAlternativeAddress), ]); diff --git a/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts b/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts index 72a894ce58..d03e91afbd 100644 --- a/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts +++ b/indexer/packages/postgres/src/stores/subaccount-usernames-table.ts @@ -97,20 +97,24 @@ export async function findByUsername( return (await baseQuery).find((subaccountUsername) => subaccountUsername.username === username); } -export async function getSubaccountsWithoutUsernames( +export async function getSubaccountZerosWithoutUsernames( + limit: number, options: Options = DEFAULT_POSTGRES_OPTIONS): Promise { const queryString: string = ` - SELECT id as "subaccountId" + SELECT id as "subaccountId", address FROM subaccounts WHERE subaccounts."subaccountNumber" = 0 - EXCEPT - SELECT "subaccountId" FROM subaccount_usernames; + AND id NOT IN ( + SELECT "subaccountId" FROM subaccount_usernames + ) + ORDER BY address + LIMIT ? `; const result: { rows: SubaccountsWithoutUsernamesResult[], - } = await rawQuery(queryString, options); + } = await rawQuery(queryString, { ...options, bindings: [limit] }); return result.rows; } diff --git a/indexer/packages/postgres/src/types/subaccount-usernames-types.ts b/indexer/packages/postgres/src/types/subaccount-usernames-types.ts index e6502776ca..c0b0eb25f0 100644 --- a/indexer/packages/postgres/src/types/subaccount-usernames-types.ts +++ b/indexer/packages/postgres/src/types/subaccount-usernames-types.ts @@ -12,4 +12,5 @@ export enum SubaccountUsernamesColumns { export interface SubaccountsWithoutUsernamesResult { subaccountId: string, + address: string, } diff --git a/indexer/pnpm-lock.yaml b/indexer/pnpm-lock.yaml index 98acd5cf3f..dd45073966 100644 --- a/indexer/pnpm-lock.yaml +++ b/indexer/pnpm-lock.yaml @@ -646,6 +646,7 @@ importers: '@types/luxon': ^3.0.0 '@types/node': ^18.0.3 '@types/redis': 2.8.27 + '@types/seedrandom': ^3.0.8 '@types/uuid': ^8.3.4 aws-sdk: ^2.1399.0 big.js: ^6.2.1 @@ -656,6 +657,7 @@ importers: lodash: ^4.17.21 luxon: ^3.0.1 redis: 2.8.0 + seedrandom: ^3.0.5 ts-node: ^10.8.2 tsconfig-paths: ^4.0.0 typescript: ^4.7.4 @@ -676,6 +678,7 @@ importers: lodash: 4.17.21 luxon: 3.0.1 redis: 2.8.0 + seedrandom: 3.0.5 uuid: 8.3.2 devDependencies: '@dydxprotocol-indexer/dev': link:../../packages/dev @@ -685,6 +688,7 @@ importers: '@types/luxon': 3.0.0 '@types/node': 18.0.3 '@types/redis': 2.8.27 + '@types/seedrandom': 3.0.8 '@types/uuid': 8.3.4 jest: 28.1.2_250642e41d506bccecc9f35ad915bcb5 ts-node: 10.8.2_2dd5d46eecda2aef953638919121af58 @@ -7095,6 +7099,10 @@ packages: '@types/node': 18.0.3 dev: true + /@types/seedrandom/3.0.8: + resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==} + dev: true + /@types/send/0.17.4: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: @@ -14203,6 +14211,10 @@ packages: resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} dev: false + /seedrandom/3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + dev: false + /semver/5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true diff --git a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts index c87ba90c09..9528aaec04 100644 --- a/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/affiliates-controller.ts @@ -43,7 +43,7 @@ class AffiliatesController extends Controller { async getMetadata( @Query() address: string, ): Promise { - const [walletRow, referredUserRows, subaccountRows] = await Promise.all([ + const [walletRow, referredUserRows, subaccountZeroRows] = await Promise.all([ WalletTable.findById(address), AffiliateReferredUsersTable.findByAffiliateAddress(address), SubaccountTable.findAll( @@ -65,11 +65,17 @@ class AffiliatesController extends Controller { const isAffiliate = referredUserRows !== undefined ? referredUserRows.length > 0 : false; // No need to check subaccountRows.length > 1 as subaccountNumber is unique for an address - if (subaccountRows.length === 0) { + if (subaccountZeroRows.length === 0) { // error logging will be performed by handleInternalServerError throw new UnexpectedServerError(`Subaccount 0 not found for address ${address}`); + } else if (subaccountZeroRows.length > 1) { + logger.error({ + at: 'affiliates-controller#snapshot', + message: `More than 1 username exist for address: ${address}`, + subaccountZeroRows, + }); } - const subaccountId = subaccountRows[0].id; + const subaccountId = subaccountZeroRows[0].id; // Get subaccount0 username, which is the referral code const usernameRows = await SubaccountUsernamesTable.findAll( diff --git a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts index 38c5bb7cb1..49e5fdec1f 100644 --- a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts +++ b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts @@ -1,11 +1,45 @@ -import { generateUsername } from '../../src/helpers/usernames-helper'; +import { + generateUsernameForSubaccount, +} from '../../src/helpers/usernames-helper'; describe('usernames-helper', () => { - it('Check format of username', () => { - const username: string = generateUsername(); - expect(username.match(/[A-Z]/g)).toHaveLength(2); - expect(username.match(/\d/g)).toHaveLength(3); - // check length is at the very minimum 7 - expect(username.length).toBeGreaterThanOrEqual(7); + it('Check result and determinism of username username', () => { + const addresses = [ + 'dydx1gf4xlnpulkyex74asxxhg9ye05r28cxdd69s9u', + 'dydx10fx7sy6ywd5senxae9dwytf8jxek3t2gcen2vs', + 'dydx1t72ww7qzdx5rjlpp6cq0cqy09qlsjj7e4kpuyt', + 'dydx1wau5mja7j7zdavtfq9lu7ejef05hm6ffenlcsn', + 'dydx168pjt8rkru35239fsqvz7rzgeclakp49zx3aum', + 'dydx1df84hz7y0dd3mrqcv3vrhw9wdttelul8edqmvp', + 'dydx16h7p7f4dysrgtzptxx2gtpt5d8t834g9dj830z', + 'dydx15u9tppy5e2pdndvlrvafxqhuurj9mnpdstzj6z', + ]; + + const expectedUsernames = [ + 'CushyHand599', + 'AmpleCube324', + 'AwareFood215', + 'LoudLand654', + 'MossyStraw800', + 'BoldGap392', + 'ZoomEra454', + 'WiryFern332', + ]; + + for (let i = 0; i < addresses.length; i++) { + const address = addresses[i]; + for (let j = 0; j < 10; j++) { + const names = new Set(); + for (let k = 0; k < 10; k++) { + const username: string = generateUsernameForSubaccount(address, 0, k); + if (k === 0) { + expect(username).toEqual(expectedUsernames[i]); + } + names.add(username); + } + // for same address, difference nonce should result in different username + expect(names.size).toEqual(10); + } + } }); }); diff --git a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts index acd52fe0b1..1a7ce0dfa1 100644 --- a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts @@ -18,6 +18,7 @@ describe('subaccount-username-generator', () => { beforeEach(async () => { await testMocks.seedData(); + await testMocks.seedAdditionalSubaccounts(); }); afterAll(async () => { diff --git a/indexer/services/roundtable/package.json b/indexer/services/roundtable/package.json index ad23413ca1..eafa83be59 100644 --- a/indexer/services/roundtable/package.json +++ b/indexer/services/roundtable/package.json @@ -31,6 +31,7 @@ "lodash": "^4.17.21", "luxon": "^3.0.1", "redis": "2.8.0", + "seedrandom": "^3.0.5", "uuid": "^8.3.2" }, "devDependencies": { @@ -41,6 +42,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^18.0.3", "@types/redis": "2.8.27", + "@types/seedrandom": "^3.0.8", "@types/uuid": "^8.3.4", "jest": "^28.1.2", "redis": "2.8.0", diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index bdc8877e5c..1666898a30 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -152,6 +152,7 @@ export const configSchema = { DELETE_ZERO_PRICE_LEVELS_LOCK_MULTIPLIER: parseInteger({ default: 1 }), UNCROSS_ORDERBOOK_LOCK_MULTIPLIER: parseInteger({ default: 1 }), PNL_TICK_UPDATE_LOCK_MULTIPLIER: parseInteger({ default: 20 }), + SUBACCOUNT_USERNAME_GENERATOR_LOCK_MULTIPLIER: parseInteger({ default: 5 }), // Maximum number of running tasks - set this equal to PG_POOL_MIN in .env, default is 2 MAX_CONCURRENT_RUNNING_TASKS: parseInteger({ default: 2 }), @@ -211,7 +212,9 @@ export const configSchema = { // Subaccount username generator SUBACCOUNT_USERNAME_NUM_RANDOM_DIGITS: parseInteger({ default: 3 }), - SUBACCOUNT_USERNAME_MAX_LENGTH: parseInteger({ default: 13 }), + SUBACCOUNT_USERNAME_BATCH_SIZE: parseInteger({ default: 1000 }), + // number of attempts to generate username for a subaccount + ATTEMPT_PER_SUBACCOUNT: parseInteger({ default: 3 }), }; export default parseSchema(configSchema); diff --git a/indexer/services/roundtable/src/helpers/adjectives.json b/indexer/services/roundtable/src/helpers/adjectives.json index c9873f0aaf..d5bace1a2b 100644 --- a/indexer/services/roundtable/src/helpers/adjectives.json +++ b/indexer/services/roundtable/src/helpers/adjectives.json @@ -1,16 +1,18 @@ [ - "able", "ace", "acid", + "active", "airy", "alert", "all", - "alpha", "aloof", + "alpha", "amber", "ample", + "amused", "apt", "arcane", + "ardent", "arid", "artsy", "ashy", @@ -23,38 +25,34 @@ "beefy", "beige", "best", - "big", - "blah", - "bland", "blocky", "blue", - "bogus", "bold", "bony", - "bossy", "bouncy", "brave", "breezy", "brief", + "bright", "brisk", "broad", "bubbly", "bumpy", "busy", - "cagey", "calm", - "campy", "candid", "canny", + "caring", "casual", + "catchy", "chaotic", - "cheap", "cheeky", "cheery", "chief", "chilly", - "chubby", + "chirpy", "civil", + "classy", "clean", "clear", "close", @@ -64,11 +62,12 @@ "copper", "coral", "corny", + "cosmic", "cozy", "crafty", - "cranky", "crisp", "crusty", + "curious", "curly", "curt", "cushy", @@ -83,23 +82,28 @@ "dinky", "dizzy", "domed", + "dope", "dotty", + "dreamy", + "driven", "dry", "dull", "dusty", - "eager", "early", "earthy", "easy", + "elated", "elite", "empty", - "equal", + "epic", "exact", "exotic", "expert", "extra", "faded", "fair", + "famed", + "famous", "fancy", "far", "fast", @@ -107,9 +111,9 @@ "fine", "firm", "fishy", + "fit", "flaky", - "flat", - "flimsy", + "fluffy", "fresh", "frilly", "frosty", @@ -117,34 +121,37 @@ "full", "funny", "fuzzy", - "gauche", - "gaudy", + "gentle", "giant", "giddy", + "giving", "glad", "gnarly", + "golden", "gonzo", "good", "goofy", "grand", "great", "green", - "grim", + "grey", "gummy", "handy", "happy", - "hard", "hardy", "harsh", "hasty", "hazy", - "heavy", + "hearty", "hefty", "high", "hilly", "hip", + "holy", + "honest", "hot", "huge", + "humble", "humid", "husky", "icky", @@ -157,15 +164,18 @@ "jade", "jazzy", "jolly", + "jovial", + "joyful", "jumpy", + "just", "keen", "khaki", "kind", - "lame", "large", "last", "late", "lavish", + "lawful", "lax", "lazy", "leafy", @@ -181,6 +191,7 @@ "long", "loud", "lousy", + "loved", "low", "loyal", "lucid", @@ -194,14 +205,17 @@ "matey", "mauve", "meek", + "mellow", "merry", "mild", "misty", - "moist", + "modern", + "modest", "moral", "mossy", - "mute", "mushy", + "mute", + "mystic", "naive", "near", "neat", @@ -216,8 +230,8 @@ "obtuse", "odd", "olden", - "open", "opal", + "open", "other", "oval", "pale", @@ -228,29 +242,37 @@ "petty", "plain", "plump", + "poised", "polite", "poor", + "prime", + "proper", "proud", "pure", + "purple", "quick", "quiet", + "radiant", "rapid", "rare", "raw", "ready", "real", "red", + "regal", "retro", "rich", "rigid", "ripe", + "robust", "roomy", "rosy", "rough", "round", - "rude", "royal", + "rude", "rusty", + "sacred", "sad", "safe", "salty", @@ -259,7 +281,9 @@ "sane", "sassy", "scaly", + "secure", "sepia", + "serene", "shaky", "sharp", "shiny", @@ -269,13 +293,14 @@ "silly", "slack", "sleek", + "sleepy", "slick", - "slim", "slow", "small", "smart", - "smug", + "smiley", "smooth", + "smug", "snappy", "snug", "soft", @@ -293,6 +318,9 @@ "still", "stout", "stuffy", + "sturdy", + "suave", + "subtle", "sunny", "super", "sweet", @@ -306,25 +334,23 @@ "tasty", "taupe", "teal", - "tepid", "tense", - "thick", + "tepid", "thin", "tidy", "tiny", "tired", "tough", + "trendy", "trim", "true", - "tubby", "twisty", - "udder", "ultra", "umber", "unique", "unruly", "untidy", - "unzip", + "upbeat", "upper", "urban", "used", @@ -336,9 +362,9 @@ "vexed", "vital", "vivid", + "vocal", "wacky", "warm", - "weak", "weary", "wide", "windy", @@ -348,12 +374,10 @@ "witty", "wooly", "woozy", - "yappy", "yummy", "zany", "zero", "zesty", - "zingy", "zippy", "zoom" ] diff --git a/indexer/services/roundtable/src/helpers/nouns.json b/indexer/services/roundtable/src/helpers/nouns.json index 63afed6d28..c923cb65c5 100644 --- a/indexer/services/roundtable/src/helpers/nouns.json +++ b/indexer/services/roundtable/src/helpers/nouns.json @@ -1,240 +1,584 @@ [ + "accent", + "access", "ace", "acorn", "act", + "actor", + "advice", + "agenda", + "agent", "air", + "alarm", + "alley", + "altar", + "amber", + "amount", + "angle", "ant", + "anthem", "apple", + "april", + "arch", + "area", + "argue", "arm", + "army", + "arrow", "art", + "artist", + "asia", "atom", + "author", + "award", "axe", + "baby", + "back", + "badge", + "badger", "bag", + "baker", "ball", + "ballet", + "banana", "band", "bank", - "bark", + "bar", "base", - "bath", - "bead", - "beam", - "bean", + "beach", "bear", + "beat", + "beaver", "bed", "bee", + "beef", + "beer", "bell", "belt", + "bench", + "berry", + "best", + "bet", + "bike", + "bill", "bird", + "bite", "blade", + "blast", + "block", "boat", + "bond", "bone", "book", "boot", - "bowl", + "born", + "boss", + "bow", "box", + "brain", + "brake", + "brand", + "brass", "bread", + "break", "brick", - "brush", + "brief", + "buffalo", "bulb", + "bull", + "bump", "bus", + "bush", + "button", + "buy", + "cab", "cake", + "call", + "calm", + "camel", + "camp", "can", + "candle", "cap", "car", "card", + "care", + "cargo", "cart", + "case", + "cash", "cat", + "catch", + "cause", "cave", + "cell", + "chain", "chair", "chalk", + "chance", "chart", + "chat", + "check", "cheese", + "chef", "chess", + "chip", + "chop", + "city", + "claim", + "clap", + "class", + "claw", "clay", + "click", + "climb", "clock", "cloud", + "club", + "coach", + "coal", + "coast", "coat", + "code", "coin", "comb", + "cone", "cook", + "cool", + "coral", "cord", "cork", "corn", + "cost", + "couch", + "count", + "cover", "cow", "crab", + "crash", + "creek", + "crop", + "cross", "crow", + "crowd", "crown", + "cry", "cube", "cup", + "curb", + "curl", + "cycle", + "dance", + "day", + "dazzle", + "deal", + "deer", "desk", + "dial", + "diet", + "dig", + "dime", + "dingo", "dish", "dog", + "doll", + "dolphin", "door", "dot", - "drum", + "dove", + "draft", + "drag", + "draw", + "dream", + "dress", + "drip", + "drive", "duck", "dust", "ear", + "earth", + "eat", + "edge", "egg", + "elbow", + "elf", + "engine", + "era", "eye", - "face", + "fact", "fan", "farm", + "fax", + "feat", "fern", + "ferret", + "fiber", + "file", + "fill", + "film", "fire", "fish", + "fist", + "fix", "flag", + "flame", + "flat", "flute", + "fly", "fog", + "fold", "food", - "foot", "fork", + "form", "fox", + "frame", "frog", "fruit", + "fuel", + "fun", "game", + "gap", "gate", "gem", "gift", + "giraffe", "glass", "glove", + "glue", "goal", "goat", "gold", + "golf", + "good", + "grab", "grape", + "graph", "grass", + "gray", + "grip", + "grizzly", + "gum", + "guy", + "hall", + "hand", "hat", - "head", - "heart", + "hawk", + "heat", + "hedgie", + "heel", + "hen", "hill", + "hippo", + "hit", + "hold", + "hole", "home", + "honey", + "hood", "hook", + "hop", "horn", "horse", - "hose", + "host", + "hour", "house", + "hug", + "hull", + "humor", + "hut", + "hyena", + "ibex", "ice", + "idea", + "inch", "ink", + "inn", "iron", + "jaguar", + "jam", "jar", "jet", + "job", + "jog", + "joy", + "jump", "key", "kite", - "knee", - "knife", + "koala", + "lab", + "lace", + "lake", + "lamb", "lamp", + "land", + "law", + "layer", "leaf", + "lean", "leg", + "lemon", + "lemur", "lens", + "lid", + "life", + "lift", + "liger", + "light", + "lily", + "lime", "line", "lion", "lip", + "llama", + "load", "lock", "log", - "loop", + "look", + "lot", + "love", + "luck", "mail", "map", + "march", + "mark", "mask", "mat", - "milk", + "meal", + "melon", + "melt", + "meme", + "menu", + "mess", + "meter", + "mile", + "mill", + "mine", + "mink", "mint", "mist", + "mode", "moon", - "moss", - "moth", - "mouse", + "moose", + "mop", + "mud", "mug", "nail", - "nest", + "name", + "nap", "net", - "nose", + "news", + "ninja", "note", - "nut", - "oar", + "nugget", + "oak", + "ocean", + "oil", + "onion", + "open", + "opera", + "orange", + "orbit", + "otter", "owl", + "ox", + "pad", "page", + "paint", "pan", + "panda", + "park", + "pass", + "path", + "paw", "pea", + "peace", "peach", "pear", "pen", - "pig", + "pencil", + "penny", + "pet", + "phone", + "photo", + "piano", + "pick", + "pie", "pin", "pipe", + "pit", "plan", - "plane", "plant", "plate", "plum", - "pool", - "pot", + "pod", + "poem", + "poet", + "pond", + "pop", + "popcorn", + "port", + "post", + "pound", + "print", + "pump", + "pup", + "quiz", + "rail", "rain", - "rat", + "ramp", + "ray", + "reef", + "rice", + "ride", "ring", + "river", "road", "rock", + "rod", + "roll", "roof", "room", "root", "rope", "rose", - "rug", + "row", + "rule", + "safe", "sail", + "salad", "salt", "sand", - "sea", + "saw", + "scale", + "scarf", + "seal", "seed", + "set", + "sew", + "shade", + "sheep", + "shell", "ship", "shoe", "shop", + "show", + "side", "sign", "silk", - "sink", + "sir", + "sit", + "ski", "sky", "sled", + "slip", + "slow", + "smile", + "smoke", + "snap", "snow", "soap", "sock", "sofa", + "soil", + "song", + "soul", + "sound", "soup", + "soy", + "space", + "spark", + "speed", + "spell", + "spin", + "spoon", + "spot", + "spring", + "spy", + "stack", + "stage", "star", - "stem", "step", "stew", - "stove", + "store", + "storm", + "straw", + "sum", + "summer", "sun", "swan", - "table", + "tag", "tail", + "tan", + "tank", + "tap", + "task", "tea", + "team", + "tear", "tent", + "thorn", + "thread", "tie", - "tire", + "tiger", + "time", + "tin", + "tip", "toe", - "tomb", "tool", - "tooth", "top", "toy", + "track", + "train", + "trap", "tree", + "trick", + "trip", + "truck", "tub", + "tug", + "tune", + "turtle", + "twig", + "twin", + "twist", + "type", + "unicorn", + "unit", + "van", "vase", + "veil", + "vein", "vest", - "wall", + "vine", + "vodka", + "voice", + "vote", + "war", "wave", - "weed", + "wax", + "web", "well", + "whale", "wheel", + "whip", + "win", + "wind", + "wine", "wing", + "winter", "wire", + "wish", "wolf", + "wombat", "wood", "wool", - "worm", - "yard", + "word", + "work", + "wrap", "yarn", + "year", + "yolk", "yoyo", "zebra", - "zero", "zoo" ] diff --git a/indexer/services/roundtable/src/helpers/usernames-helper.ts b/indexer/services/roundtable/src/helpers/usernames-helper.ts index e668d46a2b..798790733b 100644 --- a/indexer/services/roundtable/src/helpers/usernames-helper.ts +++ b/indexer/services/roundtable/src/helpers/usernames-helper.ts @@ -1,13 +1,18 @@ -import { randomInt } from 'crypto'; +import seedrandom from 'seedrandom'; import config from '../config'; import adjectives from './adjectives.json'; import nouns from './nouns.json'; -export function generateUsername(): string { - const randomAdjective: string = adjectives[randomInt(0, adjectives.length)]; - const randomNoun: string = nouns[randomInt(0, nouns.length)]; - const randomNumber: string = randomInt(0, 1000).toString().padStart( +export function generateUsernameForSubaccount( + subaccountId: string, + subaccountNum: number, + nounce: number = 0, // incremented in case of collision +): string { + const rng = seedrandom(`${subaccountId}/${subaccountNum}/${nounce}`); + const randomAdjective: string = adjectives[Math.floor(rng() * adjectives.length)]; + const randomNoun: string = nouns[Math.floor(rng() * nouns.length)]; + const randomNumber: string = Math.floor(rng() * 1000).toString().padStart( config.SUBACCOUNT_USERNAME_NUM_RANDOM_DIGITS, '0'); const capitalizedAdjective: string = randomAdjective.charAt( diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index f52903ac19..22f1697e67 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -202,6 +202,7 @@ async function start(): Promise { subaccountUsernameGeneratorTask, 'subaccount_username_generator', config.LOOPS_INTERVAL_MS_SUBACCOUNT_USERNAME_GENERATOR, + config.SUBACCOUNT_USERNAME_GENERATOR_LOCK_MULTIPLIER, ); } diff --git a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts index 819afa5bfd..9c3d7d46ef 100644 --- a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts +++ b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts @@ -3,37 +3,74 @@ import { SubaccountUsernamesTable, SubaccountsWithoutUsernamesResult, } from '@dydxprotocol-indexer/postgres'; +import _ from 'lodash'; import config from '../config'; -import { generateUsername } from '../helpers/usernames-helper'; +import { generateUsernameForSubaccount } from '../helpers/usernames-helper'; export default async function runTask(): Promise { - const subaccounts: + const subaccountZerosWithoutUsername: SubaccountsWithoutUsernamesResult[] = await - SubaccountUsernamesTable.getSubaccountsWithoutUsernames(); - for (const subaccount of subaccounts) { - const username: string = generateUsername(); - try { - // if insert fails, try it in the next roundtable cycle - // There are roughly ~87.5 million possible usernames - // so the chance of a collision is very low - await SubaccountUsernamesTable.create({ - username, - subaccountId: subaccount.subaccountId, - }); - } catch (e) { - if (e instanceof Error && e.name === 'UniqueViolationError') { - stats.increment( - `${config.SERVICE_NAME}.subaccount-username-generator.collision`, 1); - } else { - logger.error({ - at: 'subaccount-username-generator#runTask', - message: 'Failed to insert username for subaccount', - subaccountId: subaccount.subaccountId, + SubaccountUsernamesTable.getSubaccountZerosWithoutUsernames( + config.SUBACCOUNT_USERNAME_BATCH_SIZE, + ); + let successCount: number = 0; + for (const subaccount of subaccountZerosWithoutUsername) { + for (let i = 0; i < config.ATTEMPT_PER_SUBACCOUNT; i++) { + const username: string = generateUsernameForSubaccount( + subaccount.subaccountId, + // Always use subaccountNum 0 for generation. Effectively we are + // generating one username per address. The fact that we are storing + // in the `subaccount_usernames` table is a tech debt. + 0, + // generation nonce + i, + ); + try { + await SubaccountUsernamesTable.create({ username, - error: e, + subaccountId: subaccount.subaccountId, }); + // If success, break from loop and move to next subaccount. + successCount += 1; + break; + } catch (e) { + // There are roughly ~225 million possible usernames + // so the chance of collision is very low. + if (e instanceof Error && e.name === 'UniqueViolationError') { + stats.increment( + `${config.SERVICE_NAME}.subaccount-username-generator.collision`, 1); + logger.info({ + at: 'subaccount-username-generator#runTask', + message: 'username collision', + address: subaccount.address, + subaccountId: subaccount.subaccountId, + username, + error: e, + }); + } else { + logger.error({ + at: 'subaccount-username-generator#runTask', + message: 'Failed to insert username for subaccount', + address: subaccount.address, + subaccountId: subaccount.subaccountId, + username, + error: e, + }); + } } } } + const subaccountAddresses = _.map( + subaccountZerosWithoutUsername, + (subaccount) => subaccount.address, + ); + + logger.info({ + at: 'subaccount-username-generator#runTask', + message: 'Generated usernames', + batchSize: subaccountZerosWithoutUsername.length, + successCount, + addressSample: subaccountAddresses.slice(0, 10), + }); } From de54494a0bb67a4f6cfcf5856974e4a53cc97adc Mon Sep 17 00:00:00 2001 From: vincentwschau <99756290+vincentwschau@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:50:49 -0500 Subject: [PATCH 110/120] Allow configuring day vault PnL starts. (#2570) --- .../__tests__/stores/pnl-ticks-table.test.ts | 32 ++++++- .../postgres/src/stores/pnl-ticks-table.ts | 43 +++++++++ .../api/v4/vault-controller.test.ts | 21 ++++- indexer/services/comlink/src/config.ts | 2 + .../controllers/api/v4/vault-controller.ts | 87 ++++++++++++++++--- 5 files changed, 165 insertions(+), 20 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts b/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts index 2fb699acbf..25fd8f0959 100644 --- a/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts @@ -460,22 +460,19 @@ describe('PnlTicks store', () => { interval, 7 * 24 * 60 * 60, // 1 week [defaultSubaccountId, defaultSubaccountIdWithAlternateAddress], + 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[8], createdTicks[7], createdTicks[5], - createdTicks[3], createdTicks[2], createdTicks[0], ]; // Should exclude ticks that is within the same day except for the first. const expectedDailyTicks: PnlTicksFromDatabase[] = [ - createdTicks[8], createdTicks[7], - createdTicks[3], createdTicks[2], ]; @@ -486,6 +483,33 @@ describe('PnlTicks store', () => { } }); + it('Gets latest pnl ticks for subaccounts before or at given date', async () => { + const createdTicks: PnlTicksFromDatabase[] = await setupIntervalPnlTicks(); + const latestTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getLatestPnlTick( + [defaultSubaccountId, defaultSubaccountIdWithAlternateAddress], + DateTime.fromISO(createdTicks[8].blockTime).plus({ seconds: 1 }), + ); + expect(latestTicks).toEqual([createdTicks[8], createdTicks[3]]); + }); + + it('Gets empty pnl ticks for subaccounts before or at date earlier than all pnl data', async () => { + const createdTicks: PnlTicksFromDatabase[] = await setupIntervalPnlTicks(); + const latestTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getLatestPnlTick( + [defaultSubaccountId, defaultSubaccountIdWithAlternateAddress], + DateTime.fromISO(createdTicks[0].blockTime).minus({ years: 1 }), + ); + expect(latestTicks).toEqual([]); + }); + + it('Gets empty pnl ticks for subaccounts before or at date if no subaccounts given', async () => { + const createdTicks: PnlTicksFromDatabase[] = await setupIntervalPnlTicks(); + const latestTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getLatestPnlTick( + [], + DateTime.fromISO(createdTicks[0].blockTime).plus({ years: 1 }), + ); + expect(latestTicks).toEqual([]); + }); + }); async function setupRankedPnlTicksData() { diff --git a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts index 64ef22587a..30181a751e 100644 --- a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts +++ b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts @@ -1,4 +1,5 @@ import _ from 'lodash'; +import { DateTime } from 'luxon'; import { QueryBuilder } from 'objection'; import { @@ -465,7 +466,11 @@ export async function getPnlTicksAtIntervals( interval: PnlTickInterval, timeWindowSeconds: number, subaccountIds: string[], + earliestDate: DateTime, ): Promise { + if (subaccountIds.length === 0) { + return []; + } const result: { rows: PnlTicksFromDatabase[], } = await knexReadReplica.getConnection().raw( @@ -493,6 +498,7 @@ export async function getPnlTicksAtIntervals( FROM pnl_ticks WHERE "subaccountId" IN (${subaccountIds.map((id: string) => { return `'${id}'`; }).join(',')}) AND + "blockTime" >= '${earliestDate.toUTC().toISO()}'::timestamp AND "blockTime" > NOW() - INTERVAL '${timeWindowSeconds} second' ) AS pnl_intervals WHERE @@ -505,3 +511,40 @@ export async function getPnlTicksAtIntervals( return result.rows; } + +export async function getLatestPnlTick( + subaccountIds: string[], + beforeOrAt: DateTime, +): Promise { + if (subaccountIds.length === 0) { + return []; + } + const result: { + rows: PnlTicksFromDatabase[], + } = await knexReadReplica.getConnection().raw( + ` + SELECT + DISTINCT ON ("subaccountId") + "id", + "subaccountId", + "equity", + "totalPnl", + "netTransfers", + "createdAt", + "blockHeight", + "blockTime" + FROM + pnl_ticks + WHERE + "subaccountId" in (${subaccountIds.map((id: string) => { return `'${id}'`; }).join(',')}) AND + "blockTime" <= '${beforeOrAt.toUTC().toISO()}'::timestamp + ORDER BY + "subaccountId", + "blockTime" DESC + `, + ) as unknown as { + rows: PnlTicksFromDatabase[], + }; + + return result.rows; +} 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 960e5c57b6..26304550fd 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 @@ -43,6 +43,7 @@ describe('vault-controller#V4', () => { const mainVaultEquity: number = 10000; const vaultPnlHistoryHoursPrev: number = config.VAULT_PNL_HISTORY_HOURS; const vaultPnlLastPnlWindowPrev: number = config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS; + const vaultPnlStartDatePrev: string = config.VAULT_PNL_START_DATE; beforeAll(async () => { await dbHelpers.migrate(); @@ -58,6 +59,8 @@ describe('vault-controller#V4', () => { config.VAULT_PNL_HISTORY_HOURS = 168; // Use last 48 hours to get latest pnl tick for tests. config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = 48; + // Use a time before all pnl ticks as the pnl start date. + config.VAULT_PNL_START_DATE = '2020-01-01T00:00:00Z'; await testMocks.seedData(); await perpetualMarketRefresher.updatePerpetualMarkets(); await liquidityTierRefresher.updateLiquidityTiers(); @@ -126,6 +129,7 @@ describe('vault-controller#V4', () => { await dbHelpers.clearData(); 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 () => { @@ -138,21 +142,32 @@ describe('vault-controller#V4', () => { }); it.each([ - ['no resolution', '', [1, 2], 4], - ['daily resolution', '?resolution=day', [1, 2], 4], - ['hourly resolution', '?resolution=hour', [1, 2, 3, 4], 4], + ['no resolution', '', [1, 2], 4, undefined], + ['daily resolution', '?resolution=day', [1, 2], 4, undefined], + ['hourly resolution', '?resolution=hour', [1, 2, 3, 4], 4, undefined], + ['start date adjust PnL', '?resolution=hour', [1, 2, 3, 4], 4, twoDaysAgo.toISO()], ])('Get /megavault/historicalPnl with single vault subaccount (%s)', async ( _name: string, queryParam: string, expectedTicksIndex: number[], finalTickIndex: number, + startDate: string | undefined, ) => { + if (startDate !== undefined) { + config.VAULT_PNL_START_DATE = startDate; + } await VaultTable.create({ ...testConstants.defaultVault, address: testConstants.defaultSubaccount.address, clobPairId: testConstants.defaultPerpetualMarket.clobPairId, }); const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); + // Adjust PnL by total pnl of start date + if (startDate !== undefined) { + for (const createdPnlTick of createdPnlTicks) { + createdPnlTick.totalPnl = Big(createdPnlTick.totalPnl).sub('10000').toFixed(); + } + } const finalTick: PnlTicksFromDatabase = { ...createdPnlTicks[finalTickIndex], equity: Big(vault1Equity).toFixed(), diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index bfb702abcc..c6f942b046 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -62,8 +62,10 @@ export const configSchema = { // Vaults config VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }), VAULT_PNL_HISTORY_HOURS: parseInteger({ default: 72 }), + VAULT_PNL_START_DATE: parseString({ default: '2024-01-01T00:00:00Z' }), VAULT_LATEST_PNL_TICK_WINDOW_HOURS: parseInteger({ default: 1 }), VAULT_FETCH_FUNDING_INDEX_BLOCK_WINDOWS: parseInteger({ default: 250_000 }), + }; //////////////////////////////////////////////////////////////////////////////// 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 a249b50b23..dbc4043ab8 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -101,7 +101,7 @@ class VaultController extends Controller { BlockFromDatabase, string, PnlTicksFromDatabase | undefined, - DateTime | undefined + DateTime | undefined, ] = await Promise.all([ getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, getResolution(resolution)), getVaultPositions(vaultSubaccounts), @@ -114,7 +114,6 @@ class VaultController extends Controller { `${config.SERVICE_NAME}.${controllerName}.fetch_ticks_positions_equity.timing`, Date.now() - startTicksPositions, ); - // aggregate pnlTicks for all vault subaccounts grouped by blockHeight const aggregatedPnlTicks: PnlTicksFromDatabase[] = aggregateVaultPnlTicks( vaultPnlTicks, @@ -337,13 +336,28 @@ async function getVaultSubaccountPnlTicks( windowSeconds = config.VAULT_PNL_HISTORY_HOURS * 60 * 60; // hours to seconds } - const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( - resolution, - windowSeconds, - vaultSubaccountIds, - ); + const [ + pnlTicks, + adjustByPnlTicks, + ] : [ + PnlTicksFromDatabase[], + PnlTicksFromDatabase[], + ] = await Promise.all([ + PnlTicksTable.getPnlTicksAtIntervals( + resolution, + windowSeconds, + vaultSubaccountIds, + getVautlPnlStartDate(), + ), + PnlTicksTable.getLatestPnlTick( + vaultSubaccountIds, + // Add a buffer of 10 minutes to get the first PnL tick for PnL data as PnL ticks aren't + // created exactly on the hour. + getVautlPnlStartDate().plus({ minutes: 10 }), + ), + ]); - return pnlTicks; + return adjustVaultPnlTicks(pnlTicks, adjustByPnlTicks); } async function getVaultPositions( @@ -538,14 +552,33 @@ export async function getLatestPnlTick( vaultSubaccountIds: string[], vaults: VaultFromDatabase[], ): Promise { - const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( - PnlTickInterval.hour, - config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS * 60 * 60, - vaultSubaccountIds, + const [ + pnlTicks, + adjustByPnlTicks, + ] : [ + PnlTicksFromDatabase[], + PnlTicksFromDatabase[], + ] = await Promise.all([ + PnlTicksTable.getPnlTicksAtIntervals( + PnlTickInterval.hour, + config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS * 60 * 60, + vaultSubaccountIds, + getVautlPnlStartDate(), + ), + PnlTicksTable.getLatestPnlTick( + vaultSubaccountIds, + // Add a buffer of 10 minutes to get the first PnL tick for PnL data as PnL ticks aren't + // created exactly on the hour. + getVautlPnlStartDate().plus({ minutes: 10 }), + ), + ]); + const adjustedPnlTicks: PnlTicksFromDatabase[] = adjustVaultPnlTicks( + pnlTicks, + adjustByPnlTicks, ); // Aggregate and get pnl tick closest to the hour const aggregatedTicks: PnlTicksFromDatabase[] = aggregateVaultPnlTicks( - pnlTicks, + adjustedPnlTicks, vaults, ); const filteredTicks: PnlTicksFromDatabase[] = filterOutIntervalTicks( @@ -708,6 +741,29 @@ function aggregateVaultPnlTicks( }).map((aggregatedPnlTick: AggregatedPnlTick) => { return aggregatedPnlTick.pnlTick; }); } +function adjustVaultPnlTicks( + pnlTicks: PnlTicksFromDatabase[], + pnlTicksToAdjustBy: PnlTicksFromDatabase[], +): PnlTicksFromDatabase[] { + const subaccountToPnlTick: {[subaccountId: string]: PnlTicksFromDatabase} = {}; + for (const pnlTickToAdjustBy of pnlTicksToAdjustBy) { + subaccountToPnlTick[pnlTickToAdjustBy.subaccountId] = pnlTickToAdjustBy; + } + + return pnlTicks.map((pnlTick: PnlTicksFromDatabase): PnlTicksFromDatabase => { + const adjustByPnlTick: PnlTicksFromDatabase | undefined = subaccountToPnlTick[ + pnlTick.subaccountId + ]; + if (adjustByPnlTick === undefined) { + return pnlTick; + } + return { + ...pnlTick, + totalPnl: Big(pnlTick.totalPnl).sub(Big(adjustByPnlTick.totalPnl)).toFixed(), + }; + }); +} + async function getVaultMapping(): Promise { const vaults: VaultFromDatabase[] = await VaultTable.findAll( {}, @@ -740,4 +796,9 @@ async function getVaultMapping(): Promise { return validVaultMapping; } +function getVautlPnlStartDate(): DateTime { + const startDate: DateTime = DateTime.fromISO(config.VAULT_PNL_START_DATE).toUTC(); + return startDate; +} + export default router; From 00557f6cec3dd0402cf7c2aeadf7d5d62142b7de Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Thu, 14 Nov 2024 19:00:28 -0500 Subject: [PATCH 111/120] Use alphanumeric suffix for username (#2573) --- .../__tests__/helpers/usernames-helper.test.ts | 16 ++++++++-------- indexer/services/roundtable/src/config.ts | 4 ++-- .../roundtable/src/helpers/usernames-helper.ts | 9 ++++++--- .../src/tasks/subaccount-username-generator.ts | 10 ++++++++++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts index 49e5fdec1f..5ba926245a 100644 --- a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts +++ b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts @@ -16,14 +16,14 @@ describe('usernames-helper', () => { ]; const expectedUsernames = [ - 'CushyHand599', - 'AmpleCube324', - 'AwareFood215', - 'LoudLand654', - 'MossyStraw800', - 'BoldGap392', - 'ZoomEra454', - 'WiryFern332', + 'CushyHandVE6', + 'AmpleCubeLKI', + 'AwareFoodHGP', + 'LoudLandXWV', + 'MossyStraw2JJ', + 'BoldGapOGY', + 'ZoomEraQE0', + 'WiryFernLEC', ]; for (let i = 0; i < addresses.length; i++) { diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 1666898a30..6d7efbaca6 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -211,8 +211,8 @@ export const configSchema = { STALE_ORDERBOOK_LEVEL_THRESHOLD_SECONDS: parseInteger({ default: 10 }), // Subaccount username generator - SUBACCOUNT_USERNAME_NUM_RANDOM_DIGITS: parseInteger({ default: 3 }), - SUBACCOUNT_USERNAME_BATCH_SIZE: parseInteger({ default: 1000 }), + SUBACCOUNT_USERNAME_SUFFIX_RANDOM_DIGITS: parseInteger({ default: 3 }), + SUBACCOUNT_USERNAME_BATCH_SIZE: parseInteger({ default: 2000 }), // number of attempts to generate username for a subaccount ATTEMPT_PER_SUBACCOUNT: parseInteger({ default: 3 }), }; diff --git a/indexer/services/roundtable/src/helpers/usernames-helper.ts b/indexer/services/roundtable/src/helpers/usernames-helper.ts index 798790733b..1c30e076b6 100644 --- a/indexer/services/roundtable/src/helpers/usernames-helper.ts +++ b/indexer/services/roundtable/src/helpers/usernames-helper.ts @@ -4,6 +4,8 @@ import config from '../config'; import adjectives from './adjectives.json'; import nouns from './nouns.json'; +const suffixCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + export function generateUsernameForSubaccount( subaccountId: string, subaccountNum: number, @@ -12,12 +14,13 @@ export function generateUsernameForSubaccount( const rng = seedrandom(`${subaccountId}/${subaccountNum}/${nounce}`); const randomAdjective: string = adjectives[Math.floor(rng() * adjectives.length)]; const randomNoun: string = nouns[Math.floor(rng() * nouns.length)]; - const randomNumber: string = Math.floor(rng() * 1000).toString().padStart( - config.SUBACCOUNT_USERNAME_NUM_RANDOM_DIGITS, '0'); + const randomSuffix: string = Array.from( + { length: config.SUBACCOUNT_USERNAME_SUFFIX_RANDOM_DIGITS }, + () => suffixCharacters.charAt(Math.floor(rng() * suffixCharacters.length))).join(''); const capitalizedAdjective: string = randomAdjective.charAt( 0).toUpperCase() + randomAdjective.slice(1); const capitalizedNoun: string = randomNoun.charAt(0).toUpperCase() + randomNoun.slice(1); - return `${capitalizedAdjective}${capitalizedNoun}${randomNumber}`; + return `${capitalizedAdjective}${capitalizedNoun}${randomSuffix}`; } diff --git a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts index 9c3d7d46ef..d1a435cb64 100644 --- a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts +++ b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts @@ -9,6 +9,8 @@ import config from '../config'; import { generateUsernameForSubaccount } from '../helpers/usernames-helper'; export default async function runTask(): Promise { + const start: number = Date.now(); + const subaccountZerosWithoutUsername: SubaccountsWithoutUsernamesResult[] = await SubaccountUsernamesTable.getSubaccountZerosWithoutUsernames( @@ -66,11 +68,19 @@ export default async function runTask(): Promise { (subaccount) => subaccount.address, ); + const duration = Date.now() - start; + logger.info({ at: 'subaccount-username-generator#runTask', message: 'Generated usernames', batchSize: subaccountZerosWithoutUsername.length, successCount, addressSample: subaccountAddresses.slice(0, 10), + duration, }); + + stats.timing( + `${config.SERVICE_NAME}.subaccount_username_generator`, + duration, + ); } From f408f717f348454673a01b8548f7f242b6c2c869 Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Fri, 15 Nov 2024 10:27:42 -0500 Subject: [PATCH 112/120] fix(affiliates): Generate username with address, not subaccount id (#2575) --- .../roundtable/__tests__/helpers/usernames-helper.test.ts | 8 ++++++++ .../__tests__/tasks/subaccount-username-generator.test.ts | 8 ++++++++ .../services/roundtable/src/helpers/usernames-helper.ts | 4 ++-- .../roundtable/src/tasks/subaccount-username-generator.ts | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts index 5ba926245a..d5392c2771 100644 --- a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts +++ b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts @@ -13,6 +13,10 @@ describe('usernames-helper', () => { 'dydx1df84hz7y0dd3mrqcv3vrhw9wdttelul8edqmvp', 'dydx16h7p7f4dysrgtzptxx2gtpt5d8t834g9dj830z', 'dydx15u9tppy5e2pdndvlrvafxqhuurj9mnpdstzj6z', + 'dydx1q54yvrslnu0xp4drpde6f4e0k2ap9efss5hpsd', + 'dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4', + 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf', + 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf', ]; const expectedUsernames = [ @@ -24,6 +28,10 @@ describe('usernames-helper', () => { 'BoldGapOGY', 'ZoomEraQE0', 'WiryFernLEC', + 'RudeFuel59E', + 'MacroMealFK5', + 'HappySnapWTT', + 'BumpyEdgeH5Y', ]; for (let i = 0; i < addresses.length; i++) { diff --git a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts index 1a7ce0dfa1..cceb9fe631 100644 --- a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts @@ -48,6 +48,14 @@ describe('subaccount-username-generator', () => { SubaccountUsernamesTable.findAll( {}, [], {}); + const expectedUsernames = [ + 'BumpyEdgeH5Y', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf + 'HappySnapWTT', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf + 'MacroMealFK5', // dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4 + ]; expect(subaccountsWithUsernamesAfter.length).toEqual(subaccountsLength); + for (let i = 0; i < expectedUsernames.length; i++) { + expect(subaccountsWithUsernamesAfter[i].username).toEqual(expectedUsernames[i]); + } }); }); diff --git a/indexer/services/roundtable/src/helpers/usernames-helper.ts b/indexer/services/roundtable/src/helpers/usernames-helper.ts index 1c30e076b6..2c082fa4a2 100644 --- a/indexer/services/roundtable/src/helpers/usernames-helper.ts +++ b/indexer/services/roundtable/src/helpers/usernames-helper.ts @@ -7,11 +7,11 @@ import nouns from './nouns.json'; const suffixCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; export function generateUsernameForSubaccount( - subaccountId: string, + address: string, subaccountNum: number, nounce: number = 0, // incremented in case of collision ): string { - const rng = seedrandom(`${subaccountId}/${subaccountNum}/${nounce}`); + const rng = seedrandom(`${address}/${subaccountNum}/${nounce}`); const randomAdjective: string = adjectives[Math.floor(rng() * adjectives.length)]; const randomNoun: string = nouns[Math.floor(rng() * nouns.length)]; const randomSuffix: string = Array.from( diff --git a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts index d1a435cb64..03fd93f522 100644 --- a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts +++ b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts @@ -20,7 +20,7 @@ export default async function runTask(): Promise { for (const subaccount of subaccountZerosWithoutUsername) { for (let i = 0; i < config.ATTEMPT_PER_SUBACCOUNT; i++) { const username: string = generateUsernameForSubaccount( - subaccount.subaccountId, + subaccount.address, // Always use subaccountNum 0 for generation. Effectively we are // generating one username per address. The fact that we are storing // in the `subaccount_usernames` table is a tech debt. From c51e49127116d7cad404758c30b9840a80aa8dba Mon Sep 17 00:00:00 2001 From: vincentwschau <99756290+vincentwschau@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:56:22 -0500 Subject: [PATCH 113/120] Use repeatable read for pnl tick generation. (#2578) --- indexer/services/roundtable/src/tasks/create-pnl-ticks.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts index fde4918a18..7ef1df8154 100644 --- a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts +++ b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts @@ -2,6 +2,7 @@ import { logger, stats } from '@dydxprotocol-indexer/base'; import { BlockFromDatabase, BlockTable, + IsolationLevel, PnlTicksCreateObject, PnlTicksTable, Transaction, @@ -50,8 +51,10 @@ export default async function runTask(): Promise { return; } - // Start a transaction to ensure different table reads are consistent. + // Start a transaction to ensure different table reads are consistent. Use a repeatable read + // to ensure all reads within the transaction are consistent. const txId: number = await Transaction.start(); + await Transaction.setIsolationLevel(txId, IsolationLevel.REPEATABLE_READ); let newTicksToCreate: PnlTicksCreateObject[] = []; try { await perpetualMarketRefresher.updatePerpetualMarkets(); From 25606e0619204cca54a80e93cda5e036fe3be08b Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Mon, 18 Nov 2024 12:58:11 -0500 Subject: [PATCH 114/120] =?UTF-8?q?fix(affiliate):=20Use=20DB=20transactio?= =?UTF-8?q?n=20for=20username=20generation;=20add=20more=20stats=20for=20u?= =?UTF-8?q?pdate=E2=80=A6=20(#2579)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../helpers/usernames-helper.test.ts | 89 +++++++----- .../subaccount-username-generator.test.ts | 6 +- .../roundtable/src/helpers/adjectives.json | 11 +- .../roundtable/src/helpers/nouns.json | 14 -- .../tasks/subaccount-username-generator.ts | 137 ++++++++++-------- .../src/tasks/update-affiliate-info.ts | 8 + 6 files changed, 141 insertions(+), 124 deletions(-) diff --git a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts index d5392c2771..b4d10aee69 100644 --- a/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts +++ b/indexer/services/roundtable/__tests__/helpers/usernames-helper.test.ts @@ -2,52 +2,65 @@ import { generateUsernameForSubaccount, } from '../../src/helpers/usernames-helper'; -describe('usernames-helper', () => { - it('Check result and determinism of username username', () => { - const addresses = [ - 'dydx1gf4xlnpulkyex74asxxhg9ye05r28cxdd69s9u', - 'dydx10fx7sy6ywd5senxae9dwytf8jxek3t2gcen2vs', - 'dydx1t72ww7qzdx5rjlpp6cq0cqy09qlsjj7e4kpuyt', - 'dydx1wau5mja7j7zdavtfq9lu7ejef05hm6ffenlcsn', - 'dydx168pjt8rkru35239fsqvz7rzgeclakp49zx3aum', - 'dydx1df84hz7y0dd3mrqcv3vrhw9wdttelul8edqmvp', - 'dydx16h7p7f4dysrgtzptxx2gtpt5d8t834g9dj830z', - 'dydx15u9tppy5e2pdndvlrvafxqhuurj9mnpdstzj6z', - 'dydx1q54yvrslnu0xp4drpde6f4e0k2ap9efss5hpsd', - 'dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4', - 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf', - 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf', - ]; +const addresses = [ + 'dydx1gf4xlnpulkyex74asxxhg9ye05r28cxdd69s9u', + 'dydx10fx7sy6ywd5senxae9dwytf8jxek3t2gcen2vs', + 'dydx1wau5mja7j7zdavtfq9lu7ejef05hm6ffenlcsn', + 'dydx1df84hz7y0dd3mrqcv3vrhw9wdttelul8edqmvp', + 'dydx16h7p7f4dysrgtzptxx2gtpt5d8t834g9dj830z', + 'dydx15u9tppy5e2pdndvlrvafxqhuurj9mnpdstzj6z', + 'dydx1q54yvrslnu0xp4drpde6f4e0k2ap9efss5hpsd', + 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf', + 'dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf', + 'dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4', + 'dydx1c05rgh22wg5pmaufnj8z77kla8fgrgkrth6hlj', + 'dydx1qvsqtewdxqdpj5gnkl8usqz3yplpkgs52wv4fy', +]; +describe('usernames-helper', () => { + it('Check result of generated username', () => { const expectedUsernames = [ - 'CushyHandVE6', - 'AmpleCubeLKI', - 'AwareFoodHGP', - 'LoudLandXWV', - 'MossyStraw2JJ', - 'BoldGapOGY', - 'ZoomEraQE0', - 'WiryFernLEC', - 'RudeFuel59E', - 'MacroMealFK5', - 'HappySnapWTT', - 'BumpyEdgeH5Y', + 'CurlyHallVE6', + 'AmpleCrownLKI', + 'LoneLawXWV', + 'BlueGapOGY', + 'ZippyElfQE0', + 'WindyFaxLEC', + 'RoyalFruit59E', + 'GreenSnowWTT', + 'BubblyEarH5Y', + 'LunarMatFK5', + 'SubtleDig25M', + 'HillyAccess1C7', ]; + const gotUserNames = []; for (let i = 0; i < addresses.length; i++) { const address = addresses[i]; - for (let j = 0; j < 10; j++) { - const names = new Set(); - for (let k = 0; k < 10; k++) { - const username: string = generateUsernameForSubaccount(address, 0, k); - if (k === 0) { - expect(username).toEqual(expectedUsernames[i]); - } - names.add(username); + const namesForOneAddress = new Set(); + for (let k = 0; k < 10; k++) { + const username: string = generateUsernameForSubaccount(address, 0, k); + if (k === 0) { + gotUserNames.push(username); } - // for same address, difference nonce should result in different username - expect(names.size).toEqual(10); + namesForOneAddress.add(username); + } + // for same address, difference nonce should result in different username + expect(namesForOneAddress.size).toEqual(10); + } + expect(gotUserNames).toEqual(expectedUsernames); + }); + + it('Check determinism of generated username', () => { + for (let i = 0; i < addresses.length; i++) { + const address = addresses[i]; + const namesForOneAddress = new Set(); + for (let k = 0; k < 10; k++) { + const username: string = generateUsernameForSubaccount(address, 0, 0); + namesForOneAddress.add(username); } + // for same address, difference nonce should result in different username + expect(namesForOneAddress.size).toEqual(1); } }); }); diff --git a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts index cceb9fe631..8d9d44f48a 100644 --- a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts @@ -49,9 +49,9 @@ describe('subaccount-username-generator', () => { {}, [], {}); const expectedUsernames = [ - 'BumpyEdgeH5Y', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf - 'HappySnapWTT', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf - 'MacroMealFK5', // dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4 + 'GreenSnowWTT', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf + 'BubblyEarH5Y', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf + 'LunarMatFK5', // dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4 ]; expect(subaccountsWithUsernamesAfter.length).toEqual(subaccountsLength); for (let i = 0; i < expectedUsernames.length; i++) { diff --git a/indexer/services/roundtable/src/helpers/adjectives.json b/indexer/services/roundtable/src/helpers/adjectives.json index d5bace1a2b..48f7189282 100644 --- a/indexer/services/roundtable/src/helpers/adjectives.json +++ b/indexer/services/roundtable/src/helpers/adjectives.json @@ -149,10 +149,8 @@ "hip", "holy", "honest", - "hot", "huge", "humble", - "humid", "husky", "icky", "icy", @@ -190,9 +188,7 @@ "lone", "long", "loud", - "lousy", "loved", - "low", "loyal", "lucid", "lucky", @@ -234,7 +230,6 @@ "open", "other", "oval", - "pale", "paltry", "parched", "pastel", @@ -270,7 +265,6 @@ "rough", "round", "royal", - "rude", "rusty", "sacred", "sad", @@ -349,11 +343,9 @@ "umber", "unique", "unruly", - "untidy", "upbeat", "upper", "urban", - "used", "vague", "vain", "valid", @@ -378,6 +370,5 @@ "zany", "zero", "zesty", - "zippy", - "zoom" + "zippy" ] diff --git a/indexer/services/roundtable/src/helpers/nouns.json b/indexer/services/roundtable/src/helpers/nouns.json index c923cb65c5..0055867986 100644 --- a/indexer/services/roundtable/src/helpers/nouns.json +++ b/indexer/services/roundtable/src/helpers/nouns.json @@ -71,7 +71,6 @@ "bone", "book", "boot", - "born", "boss", "bow", "box", @@ -88,7 +87,6 @@ "bull", "bump", "bus", - "bush", "button", "buy", "cab", @@ -197,7 +195,6 @@ "dust", "ear", "earth", - "eat", "edge", "egg", "elbow", @@ -214,7 +211,6 @@ "ferret", "fiber", "file", - "fill", "film", "fire", "fish", @@ -226,7 +222,6 @@ "flute", "fly", "fog", - "fold", "food", "fork", "form", @@ -238,7 +233,6 @@ "fun", "game", "gap", - "gate", "gem", "gift", "giraffe", @@ -270,8 +264,6 @@ "hill", "hippo", "hit", - "hold", - "hole", "home", "honey", "hood", @@ -348,7 +340,6 @@ "melt", "meme", "menu", - "mess", "meter", "mile", "mill", @@ -466,15 +457,11 @@ "sign", "silk", "sir", - "sit", "ski", "sky", "sled", - "slip", - "slow", "smile", "smoke", - "snap", "snow", "soap", "sock", @@ -502,7 +489,6 @@ "store", "storm", "straw", - "sum", "summer", "sun", "swan", diff --git a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts index 03fd93f522..44b0db8f92 100644 --- a/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts +++ b/indexer/services/roundtable/src/tasks/subaccount-username-generator.ts @@ -2,6 +2,7 @@ import { logger, stats } from '@dydxprotocol-indexer/base'; import { SubaccountUsernamesTable, SubaccountsWithoutUsernamesResult, + Transaction, } from '@dydxprotocol-indexer/postgres'; import _ from 'lodash'; @@ -9,78 +10,96 @@ import config from '../config'; import { generateUsernameForSubaccount } from '../helpers/usernames-helper'; export default async function runTask(): Promise { - const start: number = Date.now(); + const taskStart: number = Date.now(); const subaccountZerosWithoutUsername: SubaccountsWithoutUsernamesResult[] = await SubaccountUsernamesTable.getSubaccountZerosWithoutUsernames( config.SUBACCOUNT_USERNAME_BATCH_SIZE, ); - let successCount: number = 0; - for (const subaccount of subaccountZerosWithoutUsername) { - for (let i = 0; i < config.ATTEMPT_PER_SUBACCOUNT; i++) { - const username: string = generateUsernameForSubaccount( - subaccount.address, - // Always use subaccountNum 0 for generation. Effectively we are - // generating one username per address. The fact that we are storing - // in the `subaccount_usernames` table is a tech debt. - 0, - // generation nonce - i, - ); - try { - await SubaccountUsernamesTable.create({ - username, - subaccountId: subaccount.subaccountId, - }); - // If success, break from loop and move to next subaccount. - successCount += 1; - break; - } catch (e) { - // There are roughly ~225 million possible usernames - // so the chance of collision is very low. - if (e instanceof Error && e.name === 'UniqueViolationError') { - stats.increment( - `${config.SERVICE_NAME}.subaccount-username-generator.collision`, 1); - logger.info({ - at: 'subaccount-username-generator#runTask', - message: 'username collision', - address: subaccount.address, - subaccountId: subaccount.subaccountId, + stats.timing( + `${config.SERVICE_NAME}.get_subaccount_zeros_without_usernames.timing`, + Date.now() - taskStart, + ); + + const txId: number = await Transaction.start(); + const txnStart: number = Date.now(); + try { + let successCount: number = 0; + for (const subaccount of subaccountZerosWithoutUsername) { + for (let i = 0; i < config.ATTEMPT_PER_SUBACCOUNT; i++) { + const username: string = generateUsernameForSubaccount( + subaccount.address, + // Always use subaccountNum 0 for generation. Effectively we are + // generating one username per address. The fact that we are storing + // in the `subaccount_usernames` table is a tech debt. + 0, + // generation nonce + i, + ); + try { + await SubaccountUsernamesTable.create({ username, - error: e, - }); - } else { - logger.error({ - at: 'subaccount-username-generator#runTask', - message: 'Failed to insert username for subaccount', - address: subaccount.address, subaccountId: subaccount.subaccountId, - username, - error: e, - }); + }, { txId }); + // If success, break from loop and move to next subaccount. + successCount += 1; + break; + } catch (e) { + // There are roughly ~225 million possible usernames + // so the chance of collision is very low. + if (e instanceof Error && e.name === 'UniqueViolationError') { + stats.increment( + `${config.SERVICE_NAME}.subaccount-username-generator.collision`, 1); + logger.info({ + at: 'subaccount-username-generator#runTask', + message: 'username collision', + address: subaccount.address, + subaccountId: subaccount.subaccountId, + username, + error: e, + }); + } else { + logger.error({ + at: 'subaccount-username-generator#runTask', + message: 'Failed to insert username for subaccount', + address: subaccount.address, + subaccountId: subaccount.subaccountId, + username, + error: e, + }); + } } } } + await Transaction.commit(txId); + const subaccountAddresses = _.map( + subaccountZerosWithoutUsername, + (subaccount) => subaccount.address, + ); + stats.timing( + `${config.SERVICE_NAME}.subaccount_username_generator.txn.timing`, + Date.now() - txnStart, + ); + logger.info({ + at: 'subaccount-username-generator#runTask', + message: 'Generated usernames', + batchSize: subaccountZerosWithoutUsername.length, + successCount, + addressSample: subaccountAddresses.slice(0, 10), + duration: Date.now() - taskStart, + }); + } catch (error) { + await Transaction.rollback(txId); + logger.error({ + at: 'subaccount-username-generator#runTask', + message: 'Error when updating totalVolume in wallets table', + error, + }); } - const subaccountAddresses = _.map( - subaccountZerosWithoutUsername, - (subaccount) => subaccount.address, - ); - - const duration = Date.now() - start; - - logger.info({ - at: 'subaccount-username-generator#runTask', - message: 'Generated usernames', - batchSize: subaccountZerosWithoutUsername.length, - successCount, - addressSample: subaccountAddresses.slice(0, 10), - duration, - }); stats.timing( - `${config.SERVICE_NAME}.subaccount_username_generator`, - duration, + `${config.SERVICE_NAME}.subaccount_username_generator.total.timing`, + Date.now() - taskStart, ); } diff --git a/indexer/services/roundtable/src/tasks/update-affiliate-info.ts b/indexer/services/roundtable/src/tasks/update-affiliate-info.ts index e3546eeec9..03fa4ef753 100644 --- a/indexer/services/roundtable/src/tasks/update-affiliate-info.ts +++ b/indexer/services/roundtable/src/tasks/update-affiliate-info.ts @@ -18,6 +18,7 @@ const defaultLastUpdateTime: string = '2024-09-16T00:00:00Z'; * Update the affiliate info for all affiliate addresses. */ export default async function runTask(): Promise { + const taskStart: number = Date.now(); // Wrap getting cache, updating info, and setting cache in one transaction so that persistent // cache and affilitate info table are in sync. const txId: number = await Transaction.start(); @@ -55,6 +56,7 @@ export default async function runTask(): Promise { at: 'update-affiliate-info#runTask', message: `Updating affiliate info from ${windowStartTime.toISO()} to ${windowEndTime.toISO()}`, }); + const updateAffiliateInfoStartTime: number = Date.now(); await AffiliateInfoTable.updateInfo(windowStartTime.toISO(), windowEndTime.toISO(), txId); await PersistentCacheTable.upsert({ key: PersistentCacheKeys.AFFILIATE_INFO_UPDATE_TIME, @@ -62,6 +64,10 @@ export default async function runTask(): Promise { }, { txId }); await Transaction.commit(txId); + stats.timing( + `${config.SERVICE_NAME}.update-affiliate-info.update-txn.timing`, + Date.now() - updateAffiliateInfoStartTime, + ); } catch (error) { await Transaction.rollback(txId); logger.error({ @@ -70,4 +76,6 @@ export default async function runTask(): Promise { error, }); } + + stats.timing(`${config.SERVICE_NAME}.update-affiliate-info.total.timing`, Date.now() - taskStart); } From e92fb1a21750056cd4eaac5ff2d42bd0d0d80faf Mon Sep 17 00:00:00 2001 From: Teddy Ding Date: Mon, 18 Nov 2024 13:21:41 -0500 Subject: [PATCH 115/120] Fix username generator unit test (#2582) --- .../__tests__/tasks/subaccount-username-generator.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts index 8d9d44f48a..e6785959c1 100644 --- a/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/subaccount-username-generator.test.ts @@ -49,8 +49,8 @@ describe('subaccount-username-generator', () => { {}, [], {}); const expectedUsernames = [ - 'GreenSnowWTT', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf - 'BubblyEarH5Y', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf + 'BubblyEarH5Y', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf + 'GreenSnowWTT', // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf 'LunarMatFK5', // dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4 ]; expect(subaccountsWithUsernamesAfter.length).toEqual(subaccountsLength); From dc464476c6db7748f696ff1902bf9c3a21a072f0 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Fri, 4 Oct 2024 16:48:39 -0400 Subject: [PATCH 116/120] Modify OrderbookMidPrice cache to cache multiple markets at once --- .../caches/orderbook-mid-prices-cache.test.ts | 297 +++++++++++++----- .../src/caches/orderbook-mid-prices-cache.ts | 171 +++++----- indexer/packages/redis/src/caches/scripts.ts | 8 +- .../redis/src/scripts/add_market_price.lua | 17 - .../src/scripts/add_orderbook_mid_prices.lua | 38 +++ .../src/scripts/get_market_median_price.lua | 22 -- .../src/scripts/get_orderbook_mid_prices.lua | 10 + .../__tests__/lib/candles-generator.test.ts | 34 +- .../tasks/cache-orderbook-mid-prices.test.ts | 97 ++++++ .../src/tasks/cache-orderbook-mid-prices.ts | 30 ++ 10 files changed, 518 insertions(+), 206 deletions(-) delete mode 100644 indexer/packages/redis/src/scripts/add_market_price.lua create mode 100644 indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua delete mode 100644 indexer/packages/redis/src/scripts/get_market_median_price.lua create mode 100644 indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua create mode 100644 indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts create mode 100644 indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts diff --git a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts index 5dfd662f68..089693e99a 100644 --- a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts +++ b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts @@ -1,24 +1,50 @@ import { deleteAllAsync } from '../../src/helpers/redis'; import { redis as client } from '../helpers/utils'; import { - setPrice, - getMedianPrice, + fetchAndCacheOrderbookMidPrices, + getMedianPrices, ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX, } from '../../src/caches/orderbook-mid-prices-cache'; +import * as OrderbookLevelsCache from '../../src/caches/orderbook-levels-cache'; + +// Mock the OrderbookLevelsCache module +jest.mock('../../src/caches/orderbook-levels-cache', () => ({ + getOrderBookMidPrice: jest.fn(), +})); describe('orderbook-mid-prices-cache', () => { - const ticker: string = 'BTC-USD'; + const defaultTicker: string = 'BTC-USD'; + + // Helper function to set a price for a given market ticker + const setPrice = (marketTicker: string, price: string) => { + const now = Date.now(); + client.zadd(`${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${marketTicker}`, now, price); + }; + + afterAll(async () => { + await deleteAllAsync(client); + }); beforeEach(async () => { await deleteAllAsync(client); + jest.resetAllMocks(); + (OrderbookLevelsCache.getOrderBookMidPrice as jest.Mock).mockReset(); }); - describe('setPrice', () => { + describe('fetchAndCacheOrderbookMidPrices', () => { it('sets a price for a ticker', async () => { - await setPrice(client, ticker, '50000'); + (OrderbookLevelsCache.getOrderBookMidPrice as jest.Mock).mockResolvedValue('50000'); + + await fetchAndCacheOrderbookMidPrices(client, [defaultTicker]); - await client.zrange( - `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(1); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledWith( + `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${defaultTicker}`, + client, + ); + + client.zrange( + `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${defaultTicker}`, 0, -1, (_: any, response: string[]) => { @@ -28,109 +54,238 @@ describe('orderbook-mid-prices-cache', () => { }); it('sets multiple prices for a ticker', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - ]); - - await client.zrange( - `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${ticker}`, + const mockPrices = ['49000', '50000', '51000']; + for (const price of mockPrices) { + (OrderbookLevelsCache.getOrderBookMidPrice as jest.Mock).mockResolvedValue(price); + await fetchAndCacheOrderbookMidPrices(client, [defaultTicker]); + } + + client.zrange( + `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${defaultTicker}`, 0, -1, (_: any, response: string[]) => { - expect(response).toEqual(['49000', '50000', '51000']); + expect(response).toEqual(mockPrices); }, ); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(3); + }); + + it('sets prices for multiple tickers', async () => { + const ticker2 = 'SHIB-USD'; + const ticker3 = 'SOL-USD'; + const mockPrices = { + [defaultTicker]: '49000', + [ticker2]: '50000', + [ticker3]: '51000', + }; + + // Mock the getOrderBookMidPrice function for each ticker + (OrderbookLevelsCache.getOrderBookMidPrice as jest.Mock) + .mockResolvedValueOnce(mockPrices[defaultTicker]) + .mockResolvedValueOnce(mockPrices[ticker2]) + .mockResolvedValueOnce(mockPrices[ticker3]); + + await fetchAndCacheOrderbookMidPrices(client, [defaultTicker, ticker2, ticker3]); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(3); + + for (const [key, price] of Object.entries(mockPrices)) { + client.zrange(`${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${key}`, + 0, + -1, + (err: Error, res: string[]) => { + expect(res).toHaveLength(1); + expect(res[0]).toEqual(price); + }); + } }); }); describe('getMedianPrice', () => { + it('returns null when no prices are set', async () => { - const result = await getMedianPrice(client, ticker); - expect(result).toBeNull(); + const result = await getMedianPrices(client, [defaultTicker]); + expect(result).toEqual({ 'BTC-USD': undefined }); }); it('returns the median price for odd number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - ]); - - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50000'); + setPrice(defaultTicker, '51000'); + setPrice(defaultTicker, '50000'); + setPrice(defaultTicker, '49000'); + + const result = await getMedianPrices(client, [defaultTicker]); + expect(result).toEqual({ 'BTC-USD': '50000' }); }); it('returns the median price for even number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - setPrice(client, ticker, '49000'), - setPrice(client, ticker, '52000'), - ]); - - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50500'); + setPrice(defaultTicker, '50000'); + setPrice(defaultTicker, '51000'); + setPrice(defaultTicker, '49000'); + setPrice(defaultTicker, '52000'); + + const result = await getMedianPrices(client, [defaultTicker]); + expect(result).toEqual({ 'BTC-USD': '50500' }); }); it('returns the correct median price after 5 seconds', async () => { jest.useFakeTimers(); + // Mock the getOrderBookMidPrice function for the ticker + const mockPrices = ['50000', '51000', '49000', '48000', '52000', '53000']; - const nowSeconds = Math.floor(Date.now() / 1000); - jest.setSystemTime(nowSeconds * 1000); + (OrderbookLevelsCache.getOrderBookMidPrice as jest.Mock) + .mockResolvedValueOnce(mockPrices[0]) + .mockResolvedValueOnce(mockPrices[1]) + .mockResolvedValueOnce(mockPrices[2]) + .mockResolvedValueOnce(mockPrices[3]) + .mockResolvedValueOnce(mockPrices[4]) + .mockResolvedValueOnce(mockPrices[5]); - await Promise.all([ - setPrice(client, ticker, '50000'), - setPrice(client, ticker, '51000'), - ]); + // Fetch and cache initial prices + await fetchAndCacheOrderbookMidPrices(client, [defaultTicker, defaultTicker]); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(2); + // Advance time and fetch more prices jest.advanceTimersByTime(6000); // Advance time by 6 seconds - await Promise.all([ - setPrice(client, ticker, '49000'), - setPrice(client, ticker, '48000'), - setPrice(client, ticker, '52000'), - setPrice(client, ticker, '53000'), - ]); + await fetchAndCacheOrderbookMidPrices( + client, + [defaultTicker, defaultTicker, defaultTicker, defaultTicker], + ); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(6); - const result = await getMedianPrice(client, ticker); - expect(result).toBe('50500'); + // Check the median price + const result = await getMedianPrices(client, [defaultTicker]); + // Median of last 4 prices, as first two should have expired after moving clock forward + expect(result).toEqual({ 'BTC-USD': '50500' }); jest.useRealTimers(); }); it('returns the correct median price for small numbers with even number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '0.00000000002345'), - setPrice(client, ticker, '0.00000000002346'), - ]); + setPrice(defaultTicker, '0.00000000002345'); + setPrice(defaultTicker, '0.00000000002346'); - const midPrice1 = await getMedianPrice(client, ticker); - expect(midPrice1).toEqual('0.000000000023455'); + const midPrice1 = await getMedianPrices(client, [defaultTicker]); + expect(midPrice1).toEqual({ 'BTC-USD': '0.000000000023455' }); }); it('returns the correct median price for small numbers with odd number of prices', async () => { - await Promise.all([ - setPrice(client, ticker, '0.00000000001'), - setPrice(client, ticker, '0.00000000002'), - setPrice(client, ticker, '0.00000000003'), - setPrice(client, ticker, '0.00000000004'), - setPrice(client, ticker, '0.00000000005'), - ]); + setPrice(defaultTicker, '0.00000000001'); + setPrice(defaultTicker, '0.00000000002'); + setPrice(defaultTicker, '0.00000000003'); + setPrice(defaultTicker, '0.00000000004'); + setPrice(defaultTicker, '0.00000000005'); + + const midPrice1 = await getMedianPrices(client, [defaultTicker]); + expect(midPrice1).toEqual({ 'BTC-USD': '0.00000000003' }); + + await deleteAllAsync(client); - const midPrice1 = await getMedianPrice(client, ticker); - expect(midPrice1).toEqual('0.00000000003'); + setPrice(defaultTicker, '0.00000847007'); + setPrice(defaultTicker, '0.00000847006'); + setPrice(defaultTicker, '0.00000847008'); + const midPrice2 = await getMedianPrices(client, [defaultTicker]); + expect(midPrice2).toEqual({ 'BTC-USD': '0.00000847007' }); + }); + }); + + describe('getMedianPrices for multiple markets', () => { + const btcUsdTicker = 'BTC-USD'; + const ethUsdTicker = 'ETH-USD'; + const solUsdTicker = 'SOL-USD'; + + beforeEach(async () => { await deleteAllAsync(client); + }); + + it('returns correct median prices for multiple markets with odd number of prices', async () => { + // Set prices for BTC-USD + setPrice(btcUsdTicker, '50000'); + setPrice(btcUsdTicker, '51000'); + setPrice(btcUsdTicker, '49000'); + + // Set prices for ETH-USD + setPrice(ethUsdTicker, '3000'); + setPrice(ethUsdTicker, '3100'); + setPrice(ethUsdTicker, '2900'); + + // Set prices for SOL-USD + setPrice(solUsdTicker, '100'); + setPrice(solUsdTicker, '102'); + setPrice(solUsdTicker, '98'); + + const result = await getMedianPrices(client, [btcUsdTicker, ethUsdTicker, solUsdTicker]); + expect(result).toEqual({ + 'BTC-USD': '50000', + 'ETH-USD': '3000', + 'SOL-USD': '100', + }); + }); + + it('returns correct median prices for multiple markets with even number of prices', async () => { + // Set prices for BTC-USD + setPrice(btcUsdTicker, '50000'); + setPrice(btcUsdTicker, '51000'); + setPrice(btcUsdTicker, '49000'); + setPrice(btcUsdTicker, '52000'); + + // Set prices for ETH-USD + setPrice(ethUsdTicker, '3000'); + setPrice(ethUsdTicker, '3100'); + setPrice(ethUsdTicker, '2900'); + setPrice(ethUsdTicker, '3200'); + + const result = await getMedianPrices(client, [btcUsdTicker, ethUsdTicker]); + expect(result).toEqual({ + 'BTC-USD': '50500', + 'ETH-USD': '3050', + }); + }); + + it('handles markets with different numbers of prices', async () => { + // Set prices for BTC-USD (odd number) + setPrice(btcUsdTicker, '50000'); + setPrice(btcUsdTicker, '51000'); + setPrice(btcUsdTicker, '49000'); + + // Set prices for ETH-USD (even number) + setPrice(ethUsdTicker, '3000'); + setPrice(ethUsdTicker, '3100'); + setPrice(ethUsdTicker, '2900'); + setPrice(ethUsdTicker, '3200'); + + // Set no prices for SOL-USD + + const result = await getMedianPrices(client, [btcUsdTicker, ethUsdTicker, solUsdTicker]); + expect(result).toEqual({ + 'BTC-USD': '50000', + 'ETH-USD': '3050', + 'SOL-USD': undefined, + }); + }); + + it('calculates correct median prices for markets with small and large numbers', async () => { + // Set prices for BTC-USD (large numbers) + setPrice(btcUsdTicker, '50000.12345'); + setPrice(btcUsdTicker, '50000.12346'); + + // Set prices for ETH-USD (medium numbers) + setPrice(ethUsdTicker, '3000.5'); + setPrice(ethUsdTicker, '3000.6'); + setPrice(ethUsdTicker, '3000.7'); - await Promise.all([ - setPrice(client, ticker, '0.00000847007'), - setPrice(client, ticker, '0.00000847006'), - setPrice(client, ticker, '0.00000847008'), - ]); + // Set prices for SOL-USD (small numbers) + setPrice(solUsdTicker, '0.00000123'); + setPrice(solUsdTicker, '0.00000124'); + setPrice(solUsdTicker, '0.00000125'); + setPrice(solUsdTicker, '0.00000126'); - const midPrice2 = await getMedianPrice(client, ticker); - expect(midPrice2).toEqual('0.00000847007'); + const result = await getMedianPrices(client, [btcUsdTicker, ethUsdTicker, solUsdTicker]); + expect(result).toEqual({ + 'BTC-USD': '50000.123455', + 'ETH-USD': '3000.6', + 'SOL-USD': '0.000001245', + }); }); }); }); diff --git a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts index ece95a3ca2..3d700d6652 100644 --- a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts +++ b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts @@ -1,9 +1,10 @@ import Big from 'big.js'; import { Callback, RedisClient } from 'redis'; +import { getOrderBookMidPrice } from './orderbook-levels-cache'; import { - addMarketPriceScript, - getMarketMedianScript, + addOrderbookMidPricesScript, + getOrderbookMidPricesScript, } from './scripts'; // Cache of orderbook prices for each clob pair @@ -20,73 +21,80 @@ function getOrderbookMidPriceCacheKey(ticker: string): string { } /** - * Adds a price to the market prices cache for a given ticker. - * Uses a Lua script to add the price with a timestamp to a sorted set in Redis. + * Fetches and caches mid prices for multiple tickers. * @param client The Redis client - * @param ticker The ticker symbol - * @param price The price to be added - * @returns A promise that resolves when the operation is complete + * @param tickers An array of ticker symbols + * @returns A promise that resolves when all prices are fetched and cached */ -export async function setPrice( +export async function fetchAndCacheOrderbookMidPrices( client: RedisClient, - ticker: string, - price: string, + tickers: string[], ): Promise { - // Number of keys for the lua script. - const numKeys: number = 1; + // Fetch midPrices and filter out undefined values + const cacheKeyPricePairs = await Promise.all( + tickers.map(async (ticker) => { + const cacheKey = getOrderbookMidPriceCacheKey(ticker); + const midPrice = await getOrderBookMidPrice(cacheKey, client); + if (midPrice !== undefined) { + return { cacheKey, midPrice }; + } + return null; // Return null for undefined midPrice + }), + ); - let evalAsync: ( - marketCacheKey: string, - ) => Promise = (marketCacheKey) => { + // Filter out null values + const validPairs = cacheKeyPricePairs.filter( + (pair): pair is { cacheKey: string, midPrice: string } => pair !== null, + ); + if (validPairs.length === 0) { + // No valid midPrices to cache + return; + } - return new Promise((resolve, reject) => { - const callback: Callback = ( - err: Error | null, - ) => { + const nowSeconds = Math.floor(Date.now() / 1000); // Current time in seconds + // Extract cache keys and prices + const priceCacheKeys = validPairs.map((pair) => pair.cacheKey); + const priceValues = validPairs.map((pair) => pair.midPrice); + + return new Promise((resolve, reject) => { + client.evalsha( + addOrderbookMidPricesScript.hash, + priceCacheKeys.length, + ...priceCacheKeys, + ...priceValues, + nowSeconds, + (err: Error | null) => { if (err) { - return reject(err); + reject(err); + } else { + resolve(); } - return resolve(); - }; - - const nowSeconds = Math.floor(Date.now() / 1000); // Current time in seconds - client.evalsha( - addMarketPriceScript.hash, - numKeys, - marketCacheKey, - price, - nowSeconds, - callback, - ); - - }); - }; - evalAsync = evalAsync.bind(client); - - return evalAsync( - getOrderbookMidPriceCacheKey(ticker), - ); + }, + ); + }); } /** - * Retrieves the median price for a given ticker from the cache. - * Uses a Lua script to fetch either the middle element (for odd number of prices) - * or the two middle elements (for even number of prices) from a sorted set in Redis. - * If two middle elements are returned, their average is calculated in JavaScript. + * Retrieves the median prices for a given array of tickers from the cache. * @param client The Redis client - * @param ticker The ticker symbol - * @returns A promise that resolves with the median price as a string, or null if not found + * @param tickers Array of ticker symbols + * @returns A promise that resolves with an object mapping tickers + * to their median prices (as strings) or undefined if not found */ -export async function getMedianPrice(client: RedisClient, ticker: string): Promise { +export async function getMedianPrices( + client: RedisClient, + tickers: string[], +): Promise<{ [ticker: string]: string | undefined }> { + let evalAsync: ( - marketCacheKey: string, - ) => Promise = ( - marketCacheKey, + marketCacheKeys: string[], + ) => Promise = ( + marketCacheKeys, ) => { return new Promise((resolve, reject) => { - const callback: Callback = ( + const callback: Callback = ( err: Error | null, - results: string[], + results: string[][], ) => { if (err) { return reject(err); @@ -95,33 +103,46 @@ export async function getMedianPrice(client: RedisClient, ticker: string): Promi }; client.evalsha( - getMarketMedianScript.hash, - 1, - marketCacheKey, + getOrderbookMidPricesScript.hash, // The Lua script to get cached prices + marketCacheKeys.length, + ...marketCacheKeys, callback, ); }); }; evalAsync = evalAsync.bind(client); - const prices = await evalAsync( - getOrderbookMidPriceCacheKey(ticker), - ); - - if (!prices || prices.length === 0) { - return null; - } - - if (prices.length === 1) { - return Big(prices[0]).toFixed(); - } - - if (prices.length === 2) { - const [price1, price2] = prices.map((price) => { - return Big(price); - }); - return price1.plus(price2).div(2).toFixed(); - } - - return null; + // Map tickers to cache keys + const marketCacheKeys = tickers.map(getOrderbookMidPriceCacheKey); + // Fetch the prices arrays from Redis (without scores) + const pricesArrays = await evalAsync(marketCacheKeys); + + const result: { [ticker: string]: string | undefined } = {}; + tickers.forEach((ticker, index) => { + const prices = pricesArrays[index]; + + // Check if there are any prices + if (!prices || prices.length === 0) { + result[ticker] = undefined; + return; + } + + // Convert the prices to Big.js objects for precision + const bigPrices = prices.map((price) => Big(price)); + + // Sort the prices in ascending order + bigPrices.sort((a, b) => a.cmp(b)); + + // Calculate the median + const mid = Math.floor(bigPrices.length / 2); + if (bigPrices.length % 2 === 1) { + // Odd number of prices: the middle one is the median + result[ticker] = bigPrices[mid].toFixed(); + } else { + // Even number of prices: average the two middle ones + result[ticker] = bigPrices[mid - 1].plus(bigPrices[mid]).div(2).toFixed(); + } + }); + + return result; } diff --git a/indexer/packages/redis/src/caches/scripts.ts b/indexer/packages/redis/src/caches/scripts.ts index f4f74bffd5..f9ff244e7c 100644 --- a/indexer/packages/redis/src/caches/scripts.ts +++ b/indexer/packages/redis/src/caches/scripts.ts @@ -63,8 +63,8 @@ export const removeOrderScript: LuaScript = newLuaScript('removeOrder', '../scri export const addCanceledOrderIdScript: LuaScript = newLuaScript('addCanceledOrderId', '../scripts/add_canceled_order_id.lua'); export const addStatefulOrderUpdateScript: LuaScript = newLuaScript('addStatefulOrderUpdate', '../scripts/add_stateful_order_update.lua'); export const removeStatefulOrderUpdateScript: LuaScript = newLuaScript('removeStatefulOrderUpdate', '../scripts/remove_stateful_order_update.lua'); -export const addMarketPriceScript: LuaScript = newLuaScript('addMarketPrice', '../scripts/add_market_price.lua'); -export const getMarketMedianScript: LuaScript = newLuaScript('getMarketMedianPrice', '../scripts/get_market_median_price.lua'); +export const addOrderbookMidPricesScript: LuaScript = newLuaScript('addOrderbookMidPrices', '../scripts/add_orderbook_mid_prices.lua'); +export const getOrderbookMidPricesScript: LuaScript = newLuaScript('getOrderbookMidPrices', '../scripts/get_orderbook_mid_prices.lua'); export const allLuaScripts: LuaScript[] = [ deleteZeroPriceLevelScript, @@ -77,6 +77,6 @@ export const allLuaScripts: LuaScript[] = [ addCanceledOrderIdScript, addStatefulOrderUpdateScript, removeStatefulOrderUpdateScript, - addMarketPriceScript, - getMarketMedianScript, + addOrderbookMidPricesScript, + getOrderbookMidPricesScript, ]; diff --git a/indexer/packages/redis/src/scripts/add_market_price.lua b/indexer/packages/redis/src/scripts/add_market_price.lua deleted file mode 100644 index 0e1467bb31..0000000000 --- a/indexer/packages/redis/src/scripts/add_market_price.lua +++ /dev/null @@ -1,17 +0,0 @@ --- Key for the ZSET storing price data -local priceCacheKey = KEYS[1] --- Price to be added -local price = tonumber(ARGV[1]) --- Current timestamp -local nowSeconds = tonumber(ARGV[2]) --- Time window (5 seconds) -local fiveSeconds = 5 - --- 1. Add the price to the sorted set (score is the current timestamp) -redis.call("zadd", priceCacheKey, nowSeconds, price) - --- 2. Remove any entries older than 5 seconds -local cutoffTime = nowSeconds - fiveSeconds -redis.call("zremrangebyscore", priceCacheKey, "-inf", cutoffTime) - -return true \ No newline at end of file diff --git a/indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua b/indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua new file mode 100644 index 0000000000..3b48f04150 --- /dev/null +++ b/indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua @@ -0,0 +1,38 @@ +-- KEYS contains the market cache keys +-- ARGV contains the prices for each market and a single timestamp at the end + +local numKeys = #KEYS +local numArgs = #ARGV + +-- Get the timestamp from the last argument +local timestamp = tonumber(ARGV[numArgs]) + +-- Time window (5 seconds) +local fiveSeconds = 5 + +-- Validate the timestamp +if not timestamp then + return redis.error_reply("Invalid timestamp") +end + +-- Calculate the cutoff time for removing old prices +local cutoffTime = timestamp - fiveSeconds + +-- Iterate through each key (market) and corresponding price +for i = 1, numKeys do + local priceCacheKey = KEYS[i] + local price = tonumber(ARGV[i]) + + -- Validate the price + if not price then + return redis.error_reply("Invalid price for key " .. priceCacheKey) + end + + -- Add the price to the sorted set with the current timestamp as the score + redis.call("ZADD", priceCacheKey, timestamp, price) + + -- Remove entries older than the cutoff time (older than 5 seconds) + redis.call("ZREMRANGEBYSCORE", priceCacheKey, "-inf", cutoffTime) +end + +return true diff --git a/indexer/packages/redis/src/scripts/get_market_median_price.lua b/indexer/packages/redis/src/scripts/get_market_median_price.lua deleted file mode 100644 index a318296f20..0000000000 --- a/indexer/packages/redis/src/scripts/get_market_median_price.lua +++ /dev/null @@ -1,22 +0,0 @@ --- Key for the sorted set storing price data -local priceCacheKey = KEYS[1] - --- Get all the prices from the sorted set (ascending order) -local prices = redis.call('zrange', priceCacheKey, 0, -1) - --- If no prices are found, return nil -if #prices == 0 then - return nil -end - --- Calculate the middle index -local middle = math.floor(#prices / 2) - --- Calculate median -if #prices % 2 == 0 then - -- If even, return both prices, division will be handled in Javascript - return {prices[middle], prices[middle + 1]} -else - -- If odd, return the middle element - return {prices[middle + 1]} -end diff --git a/indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua b/indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua new file mode 100644 index 0000000000..bcb9a0aa12 --- /dev/null +++ b/indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua @@ -0,0 +1,10 @@ +-- KEYS is an array of cache keys for a market + +local results = {} +for i, key in ipairs(KEYS) do + -- Get the prices for each key, but limit to a maximum of 10 + local prices = redis.call("ZRANGE", key, 0, 9) + results[i] = prices +end + +return results \ No newline at end of file diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index e9021cbf7b..842a96ab66 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -34,8 +34,8 @@ import { contentToSingleTradeMessage, createConsolidatedKafkaEventFromTrade } fr import { redisClient } from '../../src/helpers/redis/redis-controller'; import { redis, - OrderbookMidPricesCache, } from '@dydxprotocol-indexer/redis'; +import { ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX } from '@dydxprotocol-indexer/redis/build/src/caches/orderbook-mid-prices-cache'; describe('candleHelper', () => { beforeAll(async () => { @@ -61,6 +61,12 @@ describe('candleHelper', () => { jest.resetAllMocks(); }); + // Helper function to set a price for a given market ticker + const setCachePrice = (marketTicker: string, price: string) => { + const now = Date.now(); + redisClient.zadd(`${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${marketTicker}`, now, price); + }; + const defaultPrice: string = defaultTradeContent.price; const defaultPrice2: string = '15000'; const defaultCandle: CandleCreateObject = { @@ -115,11 +121,9 @@ describe('candleHelper', () => { ]); const ticker = 'BTC-USD'; - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, ticker, '100000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '105000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '110000'), - ]); + setCachePrice(ticker, '100000'); + setCachePrice(ticker, '105000'); + setCachePrice(ticker, '110000'); await runUpdateCandles(publisher); @@ -160,11 +164,9 @@ describe('candleHelper', () => { ]); const ticker = 'BTC-USD'; - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, ticker, '80000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '81000'), - OrderbookMidPricesCache.setPrice(redisClient, ticker, '80500'), - ]); + setCachePrice(ticker, '80000'); + setCachePrice(ticker, '81000'); + setCachePrice(ticker, '80500'); // Create Perpetual Position to set open position const openInterest: string = '100'; @@ -435,7 +437,7 @@ describe('candleHelper', () => { containsKafkaMessages: boolean = true, orderbookMidPrice: number, ) => { - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', orderbookMidPrice.toFixed()); + setCachePrice('BTC-USD', orderbookMidPrice.toFixed()); if (initialCandle !== undefined) { await CandleTable.create(initialCandle); @@ -673,11 +675,9 @@ describe('candleHelper', () => { }); it('successfully creates an orderbook price map for each market', async () => { - await Promise.all([ - OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '105000'), - OrderbookMidPricesCache.setPrice(redisClient, 'ISO-USD', '115000'), - OrderbookMidPricesCache.setPrice(redisClient, 'ETH-USD', '150000'), - ]); + setCachePrice('BTC-USD', '105000'); + setCachePrice('ISO-USD', '115000'); + setCachePrice('ETH-USD', '150000'); const map = await getOrderbookMidPriceMap(); expect(map).toEqual({ diff --git a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts new file mode 100644 index 0000000000..9cd50a4662 --- /dev/null +++ b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts @@ -0,0 +1,97 @@ +import { + dbHelpers, + PerpetualMarketFromDatabase, + PerpetualMarketTable, + testConstants, + testMocks, +} from '@dydxprotocol-indexer/postgres'; +import { + OrderbookLevelsCache, + OrderbookMidPricesCache, + redis, +} from '@dydxprotocol-indexer/redis'; +import { redisClient } from '../../src/helpers/redis'; +import runTask from '../../src/tasks/cache-orderbook-mid-prices'; + +describe('cache-orderbook-mid-prices', () => { + beforeEach(async () => { + await redis.deleteAllAsync(redisClient); + await testMocks.seedData(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + beforeAll(async () => { + await dbHelpers.migrate(); + await dbHelpers.clearData(); + }); + + afterEach(async () => { + await dbHelpers.clearData(); + }); + + it('caches mid prices for all markets', async () => { + const market1 = await PerpetualMarketTable + .findByMarketId( + testConstants.defaultMarket.id, + ); + const market2 = await PerpetualMarketTable + .findByMarketId( + testConstants.defaultMarket2.id, + ); + if (!market1) { + throw new Error('Market 1 not found'); + } + if (!market2) { + throw new Error('Market 2 not found'); + } + + jest.spyOn(PerpetualMarketTable, 'findAll') + .mockReturnValueOnce(Promise.resolve([ + market1, + // Passing market2 twice so that it will call getOrderbookMidPrice twice and + // cache the last two prices from the mock below + market2, + market2, + ] as PerpetualMarketFromDatabase[])); + + jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice') + .mockReturnValueOnce(Promise.resolve('200')) + .mockReturnValueOnce(Promise.resolve('300')) + .mockReturnValueOnce(Promise.resolve('400')); + + await runTask(); + + const prices = await OrderbookMidPricesCache.getMedianPrices( + redisClient, + [market1.ticker, market2.ticker], + ); + + expect(prices[market1.ticker]).toBe('200'); + expect(prices[market2.ticker]).toBe('350'); + }); + + it('handles undefined prices', async () => { + const market1 = await PerpetualMarketTable + .findByMarketId( + testConstants.defaultMarket.id, + ); + + if (!market1) { + throw new Error('Market 1 not found'); + } + + jest.spyOn(PerpetualMarketTable, 'findAll') + .mockReturnValueOnce(Promise.resolve([market1] as PerpetualMarketFromDatabase[])); + + jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice') + .mockReturnValueOnce(Promise.resolve(undefined)); + + await runTask(); + + const price = await OrderbookMidPricesCache.getMedianPrices(redisClient, [market1.ticker]); + expect(price).toEqual({ 'BTC-USD': undefined }); + }); +}); diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts new file mode 100644 index 0000000000..5dacc3d28c --- /dev/null +++ b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts @@ -0,0 +1,30 @@ +import { + logger, +} from '@dydxprotocol-indexer/base'; +import { + PerpetualMarketTable, +} from '@dydxprotocol-indexer/postgres'; +import { + OrderbookMidPricesCache, +} from '@dydxprotocol-indexer/redis'; + +import { redisClient } from '../helpers/redis'; + +/** + * Updates OrderbookMidPricesCache with current orderbook mid price for each market + */ +export default async function runTask(): Promise { + const marketTickers: string[] = (await PerpetualMarketTable.findAll({}, [])).map((market) => { + return market.ticker; + }); + + try { + await OrderbookMidPricesCache.fetchAndCacheOrderbookMidPrices(redisClient, marketTickers); + } catch (error) { + logger.error({ + at: 'cache-orderbook-mid-prices#runTask', + message: error.message, + error, + }); + } +} From 7d57b0d60aa1213b8703b4ebfd487a7a9c6802d4 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 16 Oct 2024 11:58:25 -0400 Subject: [PATCH 117/120] Add OrderbookMidPriceMemoryCache to ender and populate candles mid price values --- indexer/packages/postgres/src/index.ts | 1 + .../caches/orderbook-mid-prices-cache.test.ts | 9 +- .../src/caches/orderbook-mid-prices-cache.ts | 16 ++- .../orderbook-mid-price-memory-cache.test.ts | 83 ++++++++++++++ .../__tests__/lib/candles-generator.test.ts | 104 +++++++++--------- .../orderbook-mid-price-memory-cache.ts | 69 ++++++++++++ indexer/services/ender/src/config.ts | 2 + indexer/services/ender/src/index.ts | 5 +- .../ender/src/lib/candles-generator.ts | 14 +-- .../src/tasks/cache-orderbook-mid-prices.ts | 11 +- 10 files changed, 245 insertions(+), 69 deletions(-) create mode 100644 indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts create mode 100644 indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts diff --git a/indexer/packages/postgres/src/index.ts b/indexer/packages/postgres/src/index.ts index 70c0d719a5..fed23f558d 100644 --- a/indexer/packages/postgres/src/index.ts +++ b/indexer/packages/postgres/src/index.ts @@ -70,3 +70,4 @@ export * as testConstants from '../__tests__/helpers/constants'; export * as testConversionHelpers from '../__tests__/helpers/conversion-helpers'; export * as helpers from './db/helpers'; +export * as loopHelpers from './loops/loopHelper'; diff --git a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts index 089693e99a..6fe18b7598 100644 --- a/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts +++ b/indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts @@ -39,7 +39,7 @@ describe('orderbook-mid-prices-cache', () => { expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(1); expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledWith( - `${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${defaultTicker}`, + defaultTicker, client, ); @@ -150,6 +150,13 @@ describe('orderbook-mid-prices-cache', () => { client, [defaultTicker, defaultTicker, defaultTicker, defaultTicker], ); + + client.zrange(`${ORDERBOOK_MID_PRICES_CACHE_KEY_PREFIX}${defaultTicker}`, + 0, + -1, + (err: Error, res: string[]) => { + expect(res).toHaveLength(4); + }); expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(6); // Check the median price diff --git a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts index 3d700d6652..741789b91d 100644 --- a/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts +++ b/indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts @@ -1,3 +1,4 @@ +import { logger } from '@dydxprotocol-indexer/base'; import Big from 'big.js'; import { Callback, RedisClient } from 'redis'; @@ -34,11 +35,11 @@ export async function fetchAndCacheOrderbookMidPrices( const cacheKeyPricePairs = await Promise.all( tickers.map(async (ticker) => { const cacheKey = getOrderbookMidPriceCacheKey(ticker); - const midPrice = await getOrderBookMidPrice(cacheKey, client); + const midPrice = await getOrderBookMidPrice(ticker, client); if (midPrice !== undefined) { return { cacheKey, midPrice }; } - return null; // Return null for undefined midPrice + return null; }), ); @@ -53,8 +54,17 @@ export async function fetchAndCacheOrderbookMidPrices( const nowSeconds = Math.floor(Date.now() / 1000); // Current time in seconds // Extract cache keys and prices - const priceCacheKeys = validPairs.map((pair) => pair.cacheKey); const priceValues = validPairs.map((pair) => pair.midPrice); + const priceCacheKeys = validPairs.map((pair) => { + + logger.info({ + at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices', + message: 'Caching orderbook mid price', + cacheKey: pair.cacheKey, + midPrice: pair.midPrice, + }); + return pair.cacheKey; + }); return new Promise((resolve, reject) => { client.evalsha( diff --git a/indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts b/indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts new file mode 100644 index 0000000000..62f21dac93 --- /dev/null +++ b/indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts @@ -0,0 +1,83 @@ +import { OrderbookMidPricesCache } from '@dydxprotocol-indexer/redis'; +import * as orderbookMidPriceMemoryCache from '../../src/caches/orderbook-mid-price-memory-cache'; +import { + dbHelpers, + testMocks, +} from '@dydxprotocol-indexer/postgres'; +import config from '../../src/config'; +import { logger, stats } from '@dydxprotocol-indexer/base'; + +describe('orderbook-mid-price-memory-cache', () => { + + beforeAll(async () => { + await dbHelpers.migrate(); + await dbHelpers.clearData(); + }); + + beforeEach(async () => { + await testMocks.seedData(); + }); + + afterEach(async () => { + await dbHelpers.clearData(); + }); + + describe('getOrderbookMidPrice', () => { + it('should return the mid price for a given ticker', async () => { + jest.spyOn(OrderbookMidPricesCache, 'getMedianPrices') + .mockReturnValue(Promise.resolve({ 'BTC-USD': '300', 'ETH-USD': '200' })); + + await orderbookMidPriceMemoryCache.updateOrderbookMidPrices(); + + expect(orderbookMidPriceMemoryCache.getOrderbookMidPrice('BTC-USD')).toBe('300'); + expect(orderbookMidPriceMemoryCache.getOrderbookMidPrice('ETH-USD')).toBe('200'); + }); + }); + + describe('updateOrderbookMidPrices', () => { + it('should update the orderbook mid price cache', async () => { + const mockMedianPrices = { + 'BTC-USD': '50000', + 'ETH-USD': '3000', + 'SOL-USD': '1000', + }; + + jest.spyOn(OrderbookMidPricesCache, 'getMedianPrices') + .mockResolvedValue(mockMedianPrices); + + await orderbookMidPriceMemoryCache.updateOrderbookMidPrices(); + + expect(orderbookMidPriceMemoryCache.getOrderbookMidPrice('BTC-USD')).toBe('50000'); + expect(orderbookMidPriceMemoryCache.getOrderbookMidPrice('ETH-USD')).toBe('3000'); + expect(orderbookMidPriceMemoryCache.getOrderbookMidPrice('SOL-USD')).toBe('1000'); + }); + + it('should handle errors and log them', async () => { + const mockError = new Error('Test error'); + jest.spyOn(OrderbookMidPricesCache, 'getMedianPrices').mockImplementation(() => { + throw mockError; + }); + + jest.spyOn(logger, 'error'); + await orderbookMidPriceMemoryCache.updateOrderbookMidPrices(); + + expect(logger.error).toHaveBeenCalledWith( + expect.objectContaining({ + at: 'orderbook-mid-price-cache#updateOrderbookMidPrices', + message: 'Failed to fetch OrderbookMidPrices', + error: mockError, + }), + ); + }); + + it('should record timing stats', async () => { + jest.spyOn(stats, 'timing'); + await orderbookMidPriceMemoryCache.updateOrderbookMidPrices(); + + expect(stats.timing).toHaveBeenCalledWith( + `${config.SERVICE_NAME}.update_orderbook_mid_prices_cache.timing`, + expect.any(Number), + ); + }); + }); +}); diff --git a/indexer/services/ender/__tests__/lib/candles-generator.test.ts b/indexer/services/ender/__tests__/lib/candles-generator.test.ts index 842a96ab66..f20b68354c 100644 --- a/indexer/services/ender/__tests__/lib/candles-generator.test.ts +++ b/indexer/services/ender/__tests__/lib/candles-generator.test.ts @@ -25,6 +25,7 @@ import _ from 'lodash'; import { clearCandlesMap, getCandlesMap, startCandleCache, } from '../../src/caches/candle-cache'; +import * as OrderbookMidPriceMemoryCache from '../../src/caches/orderbook-mid-price-memory-cache'; import config from '../../src/config'; import { CandlesGenerator, getOrderbookMidPriceMap } from '../../src/lib/candles-generator'; import { KafkaPublisher } from '../../src/lib/kafka-publisher'; @@ -124,6 +125,7 @@ describe('candleHelper', () => { setCachePrice(ticker, '100000'); setCachePrice(ticker, '105000'); setCachePrice(ticker, '110000'); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); await runUpdateCandles(publisher); @@ -141,8 +143,8 @@ describe('candleHelper', () => { id: CandleTable.uuid(currentStartedAt, defaultCandle.ticker, resolution), startedAt: currentStartedAt, resolution, - orderbookMidPriceClose: null, - orderbookMidPriceOpen: null, + orderbookMidPriceClose: '105000', + orderbookMidPriceOpen: '105000', }; }, ); @@ -167,6 +169,7 @@ describe('candleHelper', () => { setCachePrice(ticker, '80000'); setCachePrice(ticker, '81000'); setCachePrice(ticker, '80500'); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); // Create Perpetual Position to set open position const openInterest: string = '100'; @@ -189,8 +192,8 @@ describe('candleHelper', () => { startedAt: currentStartedAt, resolution, startingOpenInterest: openInterest, - orderbookMidPriceClose: null, - orderbookMidPriceOpen: null, + orderbookMidPriceClose: '80500', + orderbookMidPriceOpen: '80500', }; }, ); @@ -313,8 +316,8 @@ describe('candleHelper', () => { usdVolume: '0', trades: 0, startingOpenInterest: '100', - orderbookMidPriceClose: null, - orderbookMidPriceOpen: null, + orderbookMidPriceClose: '1000', + orderbookMidPriceOpen: '1000', }, true, 1000, @@ -344,8 +347,8 @@ describe('candleHelper', () => { startedAt, resolution: CandleResolution.ONE_MINUTE, startingOpenInterest: '100', - orderbookMidPriceClose: null, - orderbookMidPriceOpen: null, + orderbookMidPriceClose: '1000', + orderbookMidPriceOpen: '1000', }, true, // contains kafka messages 1000, // orderbook mid price @@ -438,6 +441,7 @@ describe('candleHelper', () => { orderbookMidPrice: number, ) => { setCachePrice('BTC-USD', orderbookMidPrice.toFixed()); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); if (initialCandle !== undefined) { await CandleTable.create(initialCandle); @@ -481,16 +485,10 @@ describe('candleHelper', () => { const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); const orderbookMidPriceClose = '7500'; const orderbookMidPriceOpen = '8000'; - // Set candle start time to be far in the past to ensure all candles are new - const startTime: IsoString = helpers.calculateNormalizedCandleStartTime( - testConstants.createdDateTime.minus({ minutes: 100 }), - CandleResolution.ONE_MINUTE, - ).toISO(); - await Promise.all( _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { return CandleTable.create({ - startedAt: startTime, + startedAt: previousStartedAt, ticker: testConstants.defaultPerpetualMarket.ticker, resolution, low: existingPrice, @@ -508,9 +506,9 @@ describe('candleHelper', () => { ); await startCandleCache(); - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + setCachePrice('BTC-USD', '10005'); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); - // Add two trades for BTC-USD market const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([ defaultTradeKafkaEvent, @@ -518,31 +516,32 @@ describe('candleHelper', () => { ]); // Create new candles, with trades - await runUpdateCandles(publisher); - - // Verify previous candles have orderbookMidPriceClose updated - const previousExpectedCandles: CandleFromDatabase[] = _.map( - Object.values(CandleResolution), - (resolution: CandleResolution) => { - return { - id: CandleTable.uuid(startTime, defaultCandle.ticker, resolution), - startedAt: startTime, - ticker: defaultCandle.ticker, - resolution, - low: existingPrice, - high: existingPrice, - open: existingPrice, - close: existingPrice, - baseTokenVolume, - usdVolume, - trades: existingTrades, - startingOpenInterest, - orderbookMidPriceClose: '10005', - orderbookMidPriceOpen, - }; - }, - ); - await verifyCandlesInPostgres(previousExpectedCandles); + await runUpdateCandles(publisher).then(async () => { + + // Verify previous candles have orderbookMidPriceClose updated + const previousExpectedCandles: CandleFromDatabase[] = _.map( + Object.values(CandleResolution), + (resolution: CandleResolution) => { + return { + id: CandleTable.uuid(previousStartedAt, defaultCandle.ticker, resolution), + startedAt: previousStartedAt, + ticker: defaultCandle.ticker, + resolution, + low: existingPrice, + high: existingPrice, + open: existingPrice, + close: existingPrice, + baseTokenVolume, + usdVolume, + trades: existingTrades, + startingOpenInterest, + orderbookMidPriceClose: '10005', + orderbookMidPriceOpen, + }; + }, + ); + await verifyCandlesInPostgres(previousExpectedCandles); + }); // Verify new candles were created const expectedCandles: CandleFromDatabase[] = _.map( @@ -584,16 +583,11 @@ describe('candleHelper', () => { const usdVolume: string = Big(existingPrice).times(baseTokenVolume).toString(); const orderbookMidPriceClose = '7500'; const orderbookMidPriceOpen = '8000'; - // Set candle start time to be far in the past to ensure all candles are new - const startTime: IsoString = helpers.calculateNormalizedCandleStartTime( - testConstants.createdDateTime.minus({ minutes: 100 }), - CandleResolution.ONE_MINUTE, - ).toISO(); await Promise.all( _.map(Object.values(CandleResolution), (resolution: CandleResolution) => { return CandleTable.create({ - startedAt: startTime, + startedAt: previousStartedAt, ticker: testConstants.defaultPerpetualMarket.ticker, resolution, low: existingPrice, @@ -611,7 +605,8 @@ describe('candleHelper', () => { ); await startCandleCache(); - await OrderbookMidPricesCache.setPrice(redisClient, 'BTC-USD', '10005'); + setCachePrice('BTC-USD', '10005'); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); const publisher: KafkaPublisher = new KafkaPublisher(); publisher.addEvents([]); @@ -624,8 +619,8 @@ describe('candleHelper', () => { Object.values(CandleResolution), (resolution: CandleResolution) => { return { - id: CandleTable.uuid(startTime, defaultCandle.ticker, resolution), - startedAt: startTime, + id: CandleTable.uuid(previousStartedAt, defaultCandle.ticker, resolution), + startedAt: previousStartedAt, ticker: defaultCandle.ticker, resolution, low: existingPrice, @@ -678,12 +673,13 @@ describe('candleHelper', () => { setCachePrice('BTC-USD', '105000'); setCachePrice('ISO-USD', '115000'); setCachePrice('ETH-USD', '150000'); + await OrderbookMidPriceMemoryCache.updateOrderbookMidPrices(); const map = await getOrderbookMidPriceMap(); expect(map).toEqual({ - 'BTC-USD': undefined, - 'ETH-USD': undefined, - 'ISO-USD': undefined, + 'BTC-USD': '105000', + 'ETH-USD': '150000', + 'ISO-USD': '115000', 'ISO2-USD': undefined, 'SHIB-USD': undefined, }); diff --git a/indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts b/indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts new file mode 100644 index 0000000000..7a6e61998e --- /dev/null +++ b/indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts @@ -0,0 +1,69 @@ +import { logger, stats } from '@dydxprotocol-indexer/base'; +import { + PerpetualMarketFromDatabase, + perpetualMarketRefresher, + loopHelpers, +} from '@dydxprotocol-indexer/postgres'; +import { OrderbookMidPricesCache } from '@dydxprotocol-indexer/redis'; + +import config from '../config'; +import { redisClient } from '../helpers/redis/redis-controller'; + +interface OrderbookMidPriceCache { + [ticker: string]: string | undefined, +} + +let orderbookMidPriceCache: OrderbookMidPriceCache = {}; + +/** + * Refresh loop to cache the list of all perpetual markets from the database in-memory. + */ +export async function start(): Promise { + await loopHelpers.startUpdateLoop( + updateOrderbookMidPrices, + config.ORDERBOOK_MID_PRICE_REFRESH_INTERVAL_MS, + 'updateOrderbookMidPrices', + ); +} + +export function getOrderbookMidPrice(ticker: string): string | undefined { + return orderbookMidPriceCache[ticker]; +} + +export async function updateOrderbookMidPrices(): Promise { + const startTime: number = Date.now(); + try { + const perpetualMarkets: PerpetualMarketFromDatabase[] = Object.values( + perpetualMarketRefresher.getPerpetualMarketsMap(), + ); + + const tickers: string[] = perpetualMarkets.map((market) => market.ticker); + + orderbookMidPriceCache = await OrderbookMidPricesCache.getMedianPrices( + redisClient, + tickers, + ); + + // Log out each median price for each market + Object.entries(orderbookMidPriceCache).forEach(([ticker, price]) => { + logger.info({ + at: 'orderbook-mid-price-cache#updateOrderbookMidPrices', + message: `Median price for market ${ticker}`, + ticker, + price, + }); + }); + + } catch (error) { + logger.error({ + at: 'orderbook-mid-price-cache#updateOrderbookMidPrices', + message: 'Failed to fetch OrderbookMidPrices', + error, + }); + } finally { + stats.timing( + `${config.SERVICE_NAME}.update_orderbook_mid_prices_cache.timing`, + Date.now() - startTime, + ); + } +} diff --git a/indexer/services/ender/src/config.ts b/indexer/services/ender/src/config.ts index 201f7807ee..0e940650e1 100644 --- a/indexer/services/ender/src/config.ts +++ b/indexer/services/ender/src/config.ts @@ -7,6 +7,7 @@ import { baseConfigSchema, parseBoolean, parseString, + parseInteger, } from '@dydxprotocol-indexer/base'; import { kafkaConfigSchema, @@ -31,6 +32,7 @@ export const configSchema = { SKIP_STATEFUL_ORDER_UUIDS: parseString({ default: '', }), + ORDERBOOK_MID_PRICE_REFRESH_INTERVAL_MS: parseInteger({ default: 10_000 }), // 10 seconds }; export default parseSchema(configSchema); diff --git a/indexer/services/ender/src/index.ts b/indexer/services/ender/src/index.ts index c72d8542ee..07702f9b7d 100644 --- a/indexer/services/ender/src/index.ts +++ b/indexer/services/ender/src/index.ts @@ -5,6 +5,7 @@ import { } from '@dydxprotocol-indexer/postgres'; import { initializeAllCaches } from './caches/block-cache'; +import * as OrderbookMidPriceMemoryCache from './caches/orderbook-mid-price-memory-cache'; import config from './config'; import { connect } from './helpers/kafka/kafka-controller'; import { createPostgresFunctions } from './helpers/postgres/postgres-functions'; @@ -28,8 +29,10 @@ async function startKafka(): Promise { ]); // Ender does not need to refresh its caches in a loop because Ender is the only service that // writes to the key attributes of perpetual_markets, asset_refresher, and market_refresher - // The only exception are the aggregated properties of perpetual_markets + // The two exceptions are the aggregated properties of perpetual_markets and the + // OrderbookMidPriceMemoryCache await initializeAllCaches(); + wrapBackgroundTask(OrderbookMidPriceMemoryCache.start(), true, 'startUpdateOrderbookMidPrices'); await connect(); await startConsumer(); diff --git a/indexer/services/ender/src/lib/candles-generator.ts b/indexer/services/ender/src/lib/candles-generator.ts index f1daa75f06..744c17f92e 100644 --- a/indexer/services/ender/src/lib/candles-generator.ts +++ b/indexer/services/ender/src/lib/candles-generator.ts @@ -26,6 +26,7 @@ import _ from 'lodash'; import { DateTime } from 'luxon'; import { getCandle } from '../caches/candle-cache'; +import { getOrderbookMidPrice } from '../caches/orderbook-mid-price-memory-cache'; import config from '../config'; import { KafkaPublisher } from './kafka-publisher'; import { ConsolidatedKafkaEvent, SingleTradeMessage } from './types'; @@ -169,7 +170,7 @@ export class CandlesGenerator { const promises: Promise[] = []; const openInterestMap: OpenInterestMap = await this.getOpenInterestMap(); - const orderbookMidPriceMap = await getOrderbookMidPriceMap(); + const orderbookMidPriceMap = getOrderbookMidPriceMap(); _.forEach( Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()), (perpetualMarket: PerpetualMarketFromDatabase) => { @@ -531,18 +532,13 @@ export class CandlesGenerator { /** * Get the cached orderbook mid price for a given ticker */ -export async function getOrderbookMidPriceMap(): Promise<{ [ticker: string]: OrderbookMidPrice }> { +export function getOrderbookMidPriceMap(): { [ticker: string]: OrderbookMidPrice } { const start: number = Date.now(); const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()); - const promises = perpetualMarkets.map(async (perpetualMarket: PerpetualMarketFromDatabase) => { - return Promise.resolve({ [perpetualMarket.ticker]: undefined }); - }); - - const pricesArray = await Promise.all(promises); const priceMap: { [ticker: string]: OrderbookMidPrice } = {}; - pricesArray.forEach((price) => { - Object.assign(priceMap, price); + perpetualMarkets.forEach((perpetualMarket: PerpetualMarketFromDatabase) => { + priceMap[perpetualMarket.ticker] = getOrderbookMidPrice(perpetualMarket.ticker); }); stats.timing(`${config.SERVICE_NAME}.get_orderbook_mid_price_map.timing`, Date.now() - start); diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts index 5dacc3d28c..4980159a42 100644 --- a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts +++ b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts @@ -14,11 +14,20 @@ import { redisClient } from '../helpers/redis'; * Updates OrderbookMidPricesCache with current orderbook mid price for each market */ export default async function runTask(): Promise { - const marketTickers: string[] = (await PerpetualMarketTable.findAll({}, [])).map((market) => { + const marketTickers: string[] = (await PerpetualMarketTable.findAll( + {}, + [], + { readReplica: true }, + )).map((market) => { return market.ticker; }); try { + logger.info({ + at: 'cache-orderbook-mid-prices#runTask', + message: 'Caching orderbook mid prices for markets', + markets: marketTickers.join(', '), + }); await OrderbookMidPricesCache.fetchAndCacheOrderbookMidPrices(redisClient, marketTickers); } catch (error) { logger.error({ From 87916293ba0c16412f258ce51f8334d83aeab01a Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 16 Oct 2024 15:42:37 -0400 Subject: [PATCH 118/120] Temp Deploy --- .../indexer-build-and-push-dev-staging.yml | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/.github/workflows/indexer-build-and-push-dev-staging.yml b/.github/workflows/indexer-build-and-push-dev-staging.yml index 5a98b72552..1228df08bb 100644 --- a/.github/workflows/indexer-build-and-push-dev-staging.yml +++ b/.github/workflows/indexer-build-and-push-dev-staging.yml @@ -6,53 +6,14 @@ on: # yamllint disable-line rule:truthy - main - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x + - 'adam/candles-memory-cache' # TODO(DEC-837): Customize github build and push to ECR by service with paths jobs: - # Build and push to dev - call-build-and-push-ecs-services-dev: - name: (Dev) Build and Push ECS Services - uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml - with: - ENVIRONMENT: dev - secrets: inherit - # Build and push to dev2 call-build-and-push-ecs-services-dev2: name: (Dev2) Build and Push ECS Services uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml with: ENVIRONMENT: dev2 - secrets: inherit - - # Build and push to dev3 - call-build-and-push-ecs-services-dev3: - name: (Dev3) Build and Push ECS Services - uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml - with: - ENVIRONMENT: dev3 - secrets: inherit - - # Build and push to dev4 - call-build-and-push-ecs-services-dev4: - name: (Dev4) Build and Push ECS Services - uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml - with: - ENVIRONMENT: dev4 - secrets: inherit - - # Build and push to dev5 - call-build-and-push-ecs-services-dev5: - name: (Dev5) Build and Push ECS Services - uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml - with: - ENVIRONMENT: dev5 - secrets: inherit - - # Build and push to staging - call-build-and-push-ecs-services-staging: - name: (Staging) Build and Push ECS Services - uses: ./.github/workflows/indexer-build-and-push-all-ecr-images.yml - with: - ENVIRONMENT: staging - secrets: inherit + secrets: inherit \ No newline at end of file From 9ef87bc5416734995d09aec6f06aa4a872c461cc Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Mon, 28 Oct 2024 11:46:13 -0400 Subject: [PATCH 119/120] Add perpetual market refresher to roundtable --- .../tasks/cache-orderbook-mid-prices.test.ts | 29 +++++++++---------- .../src/tasks/cache-orderbook-mid-prices.ts | 15 ++++------ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts index 9cd50a4662..ad98192071 100644 --- a/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts @@ -4,6 +4,7 @@ import { PerpetualMarketTable, testConstants, testMocks, + perpetualMarketRefresher, } from '@dydxprotocol-indexer/postgres'; import { OrderbookLevelsCache, @@ -17,6 +18,7 @@ describe('cache-orderbook-mid-prices', () => { beforeEach(async () => { await redis.deleteAllAsync(redisClient); await testMocks.seedData(); + await perpetualMarketRefresher.updatePerpetualMarkets(); }); afterAll(() => { @@ -30,6 +32,7 @@ describe('cache-orderbook-mid-prices', () => { afterEach(async () => { await dbHelpers.clearData(); + await perpetualMarketRefresher.clear(); }); it('caches mid prices for all markets', async () => { @@ -41,36 +44,30 @@ describe('cache-orderbook-mid-prices', () => { .findByMarketId( testConstants.defaultMarket2.id, ); - if (!market1) { - throw new Error('Market 1 not found'); - } - if (!market2) { - throw new Error('Market 2 not found'); + const market3 = await PerpetualMarketTable + .findByMarketId( + testConstants.defaultMarket3.id, + ); + if (!market1 || !market2 || !market3) { + throw new Error('Test market not found'); } - jest.spyOn(PerpetualMarketTable, 'findAll') - .mockReturnValueOnce(Promise.resolve([ - market1, - // Passing market2 twice so that it will call getOrderbookMidPrice twice and - // cache the last two prices from the mock below - market2, - market2, - ] as PerpetualMarketFromDatabase[])); - jest.spyOn(OrderbookLevelsCache, 'getOrderBookMidPrice') .mockReturnValueOnce(Promise.resolve('200')) .mockReturnValueOnce(Promise.resolve('300')) .mockReturnValueOnce(Promise.resolve('400')); await runTask(); + expect(OrderbookLevelsCache.getOrderBookMidPrice).toHaveBeenCalledTimes(5); const prices = await OrderbookMidPricesCache.getMedianPrices( redisClient, - [market1.ticker, market2.ticker], + [market1.ticker, market2.ticker, market3.ticker], ); expect(prices[market1.ticker]).toBe('200'); - expect(prices[market2.ticker]).toBe('350'); + expect(prices[market2.ticker]).toBe('300'); + expect(prices[market3.ticker]).toBe('400'); }); it('handles undefined prices', async () => { diff --git a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts index 4980159a42..7b469deb0a 100644 --- a/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts +++ b/indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts @@ -2,7 +2,8 @@ import { logger, } from '@dydxprotocol-indexer/base'; import { - PerpetualMarketTable, + PerpetualMarketFromDatabase, + perpetualMarketRefresher, } from '@dydxprotocol-indexer/postgres'; import { OrderbookMidPricesCache, @@ -14,14 +15,10 @@ import { redisClient } from '../helpers/redis'; * Updates OrderbookMidPricesCache with current orderbook mid price for each market */ export default async function runTask(): Promise { - const marketTickers: string[] = (await PerpetualMarketTable.findAll( - {}, - [], - { readReplica: true }, - )).map((market) => { - return market.ticker; - }); - + const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap()); + const marketTickers = perpetualMarkets.map( + (market: PerpetualMarketFromDatabase) => market.ticker, + ); try { logger.info({ at: 'cache-orderbook-mid-prices#runTask', From cd80439cd217d60f404f40f5e63ce1126c4ad256 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 20 Nov 2024 13:45:38 -0500 Subject: [PATCH 120/120] Run cache orderbook mid prices roundtable task --- indexer/services/roundtable/src/config.ts | 1 + indexer/services/roundtable/src/index.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 6d7efbaca6..967b24166a 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_CACHE_ORDERBOOK_MID_PRICES: parseBoolean({ default: true }), // Loop Timing LOOPS_INTERVAL_MS_MARKET_UPDATER: parseInteger({ diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index 22f1697e67..97457b459c 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -10,6 +10,7 @@ import { connect as connectToRedis, } from './helpers/redis'; import aggregateTradingRewardsTasks from './tasks/aggregate-trading-rewards'; +import cacheOrderbookMidPrices from './tasks/cache-orderbook-mid-prices'; import cancelStaleOrdersTask from './tasks/cancel-stale-orders'; import createLeaderboardTask from './tasks/create-leaderboard'; import createPnlTicksTask from './tasks/create-pnl-ticks'; @@ -272,6 +273,13 @@ async function start(): Promise { config.LOOPS_INTERVAL_MS_DELETE_FIREBASE_NOTIFICATION_TOKENS_MONTHLY, ); } + if (config.LOOPS_ENABLED_CACHE_ORDERBOOK_MID_PRICES) { + startLoop( + cacheOrderbookMidPrices, + 'cache-orderbook-mid-prices', + config.LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES, + ); + } logger.info({ at: 'index',