From 8aa9c01c8405570e60184eabe0adc38e99ab9ee8 Mon Sep 17 00:00:00 2001 From: Jared Vu Date: Thu, 5 Dec 2024 15:24:38 -0800 Subject: [PATCH 1/8] feat: add new account endpoints (#302) --- .../__native__/__ios__/v4-native-client.js | 69 +++++++++-- v4-client-js/package-lock.json | 2 +- v4-client-js/package.json | 2 +- v4-client-js/src/clients/constants.ts | 9 +- v4-client-js/src/clients/modules/account.ts | 113 ++++++++++++++++-- 5 files changed, 169 insertions(+), 26 deletions(-) diff --git a/v4-client-js/__native__/__ios__/v4-native-client.js b/v4-client-js/__native__/__ios__/v4-native-client.js index 2decc790..1dc4190c 100644 --- a/v4-client-js/__native__/__ios__/v4-native-client.js +++ b/v4-client-js/__native__/__ios__/v4-native-client.js @@ -203994,8 +203994,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.SHORT_BLOCK_FORWARD = exports.SHORT_BLOCK_WINDOW = exports.MAX_MEMO_CHARACTERS = exports.DEFAULT_API_TIMEOUT = exports.PnlTickInterval = exports.TimePeriod = exports.PositionStatus = exports.TickerType = exports.OrderStatus = exports.OrderExecution = exports.OrderTimeInForce = exports.OrderSide = exports.OrderType = exports.MarketStatisticDay = exports.MEGAVAULT_MODULE_ADDRESS = exports.DELAYMSG_MODULE_ADDRESS = exports.GOV_MODULE_ADDRESS = exports.TYPE_URL_MSG_WITHDRAW_DELEGATOR_REWARD = exports.TYPE_URL_MSG_UNDELEGATE = exports.TYPE_URL_MSG_DELEGATE = exports.TYPE_URL_MSG_WITHDRAW_FROM_MEGAVAULT = exports.TYPE_URL_MSG_DEPOSIT_TO_MEGAVAULT = exports.TYPE_URL_MSG_REGISTER_AFFILIATE = exports.TYPE_URL_MSG_DEPOSIT_TO_SUBACCOUNT = exports.TYPE_URL_MSG_WITHDRAW_FROM_SUBACCOUNT = exports.TYPE_URL_MSG_CREATE_TRANSFER = exports.TYPE_URL_MSG_CREATE_ORACLE_MARKET = exports.TYPE_URL_MSG_CREATE_PERPETUAL = exports.TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS = exports.TYPE_URL_MSG_DELAY_MESSAGE = exports.TYPE_URL_MSG_UPDATE_CLOB_PAIR = exports.TYPE_URL_MSG_CREATE_CLOB_PAIR = exports.TYPE_URL_BATCH_CANCEL = exports.TYPE_URL_MSG_CANCEL_ORDER = exports.TYPE_URL_MSG_PLACE_ORDER = exports.TYPE_URL_MSG_SUBMIT_PROPOSAL = exports.TYPE_URL_MSG_SEND = exports.SelectedGasDenom = exports.NETWORK_ID_MAINNET = exports.NETWORK_ID_TESTNET = exports.NetworkId = exports.ValidatorApiHost = exports.FaucetApiHost = exports.IndexerWSHost = exports.IndexerApiHost = exports.MAINNET_CHAIN_ID = exports.LOCAL_CHAIN_ID = exports.TESTNET_CHAIN_ID = exports.STAGING_CHAIN_ID = exports.DEV_CHAIN_ID = void 0; -exports.Network = exports.ValidatorConfig = exports.IndexerConfig = exports.PAGE_REQUEST = void 0; +exports.SHORT_BLOCK_WINDOW = exports.MAX_MEMO_CHARACTERS = exports.DEFAULT_API_TIMEOUT = exports.TradingRewardAggregationPeriod = exports.PnlTickInterval = exports.TimePeriod = exports.PositionStatus = exports.TickerType = exports.OrderStatus = exports.OrderExecution = exports.OrderTimeInForce = exports.OrderSide = exports.OrderType = exports.MarketStatisticDay = exports.MEGAVAULT_MODULE_ADDRESS = exports.DELAYMSG_MODULE_ADDRESS = exports.GOV_MODULE_ADDRESS = exports.TYPE_URL_MSG_WITHDRAW_DELEGATOR_REWARD = exports.TYPE_URL_MSG_UNDELEGATE = exports.TYPE_URL_MSG_DELEGATE = exports.TYPE_URL_MSG_WITHDRAW_FROM_MEGAVAULT = exports.TYPE_URL_MSG_DEPOSIT_TO_MEGAVAULT = exports.TYPE_URL_MSG_REGISTER_AFFILIATE = exports.TYPE_URL_MSG_DEPOSIT_TO_SUBACCOUNT = exports.TYPE_URL_MSG_WITHDRAW_FROM_SUBACCOUNT = exports.TYPE_URL_MSG_CREATE_TRANSFER = exports.TYPE_URL_MSG_CREATE_ORACLE_MARKET = exports.TYPE_URL_MSG_CREATE_PERPETUAL = exports.TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS = exports.TYPE_URL_MSG_DELAY_MESSAGE = exports.TYPE_URL_MSG_UPDATE_CLOB_PAIR = exports.TYPE_URL_MSG_CREATE_CLOB_PAIR = exports.TYPE_URL_BATCH_CANCEL = exports.TYPE_URL_MSG_CANCEL_ORDER = exports.TYPE_URL_MSG_PLACE_ORDER = exports.TYPE_URL_MSG_SUBMIT_PROPOSAL = exports.TYPE_URL_MSG_SEND = exports.SelectedGasDenom = exports.NETWORK_ID_MAINNET = exports.NETWORK_ID_TESTNET = exports.NetworkId = exports.ValidatorApiHost = exports.FaucetApiHost = exports.IndexerWSHost = exports.IndexerApiHost = exports.MAINNET_CHAIN_ID = exports.LOCAL_CHAIN_ID = exports.TESTNET_CHAIN_ID = exports.STAGING_CHAIN_ID = exports.DEV_CHAIN_ID = void 0; +exports.Network = exports.ValidatorConfig = exports.IndexerConfig = exports.PAGE_REQUEST = exports.SHORT_BLOCK_FORWARD = void 0; const long_1 = __importDefault(__webpack_require__(/*! long */ "./node_modules/long/src/long.js")); __exportStar(__webpack_require__(/*! ../lib/constants */ "./src/lib/constants.ts"), exports); /** @@ -204169,6 +204169,12 @@ var PnlTickInterval; PnlTickInterval["HOUR"] = "hour"; PnlTickInterval["day"] = "day"; })(PnlTickInterval = exports.PnlTickInterval || (exports.PnlTickInterval = {})); +var TradingRewardAggregationPeriod; +(function (TradingRewardAggregationPeriod) { + TradingRewardAggregationPeriod["DAILY"] = "DAILY"; + TradingRewardAggregationPeriod["WEEKLY"] = "WEEKLY"; + TradingRewardAggregationPeriod["MONTHLY"] = "MONTHLY"; +})(TradingRewardAggregationPeriod = exports.TradingRewardAggregationPeriod || (exports.TradingRewardAggregationPeriod = {})); // ------------ API Defaults ------------ exports.DEFAULT_API_TIMEOUT = 3000; exports.MAX_MEMO_CHARACTERS = 256; @@ -204256,7 +204262,7 @@ class Network { } } exports.Network = Network; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaWVudHMvY29uc3RhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLGdEQUF3QjtBQUl4QixtREFBaUM7QUFFakM7Ozs7O0dBS0c7QUFFSCxXQUFXO0FBQ0UsUUFBQSxZQUFZLEdBQUcsc0JBQXNCLENBQUM7QUFDdEMsUUFBQSxnQkFBZ0IsR0FBRyxzQkFBc0IsQ0FBQztBQUMxQyxRQUFBLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO0FBQ3BDLFFBQUEsY0FBYyxHQUFHLG1CQUFtQixDQUFDO0FBQ2xELDJDQUEyQztBQUM5QixRQUFBLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO0FBRWpELHFDQUFxQztBQUNyQyxJQUFZLGNBTVg7QUFORCxXQUFZLGNBQWM7SUFDeEIsc0VBQW9ELENBQUE7SUFDcEQsc0VBQW9ELENBQUE7SUFDcEQsaURBQStCLENBQUE7SUFDL0IsMkNBQTJDO0lBQzNDLHdEQUFzQyxDQUFBO0FBQ3hDLENBQUMsRUFOVyxjQUFjLEdBQWQsc0JBQWMsS0FBZCxzQkFBYyxRQU16QjtBQUVELElBQVksYUFNWDtBQU5ELFdBQVksYUFBYTtJQUN2Qix3RUFBdUQsQ0FBQTtJQUN2RCx3RUFBdUQsQ0FBQTtJQUN2RCw4Q0FBNkIsQ0FBQTtJQUM3QiwyQ0FBMkM7SUFDM0MsMkRBQTBDLENBQUE7QUFDNUMsQ0FBQyxFQU5XLGFBQWEsR0FBYixxQkFBYSxLQUFiLHFCQUFhLFFBTXhCO0FBRUQsSUFBWSxhQUVYO0FBRkQsV0FBWSxhQUFhO0lBQ3ZCLG1FQUFrRCxDQUFBO0FBQ3BELENBQUMsRUFGVyxhQUFhLEdBQWIscUJBQWEsS0FBYixxQkFBYSxRQUV4QjtBQUVELElBQVksZ0JBTVg7QUFORCxXQUFZLGdCQUFnQjtJQUMxQixtRUFBK0MsQ0FBQTtJQUMvQyx5RUFBcUQsQ0FBQTtJQUNyRCxvREFBZ0MsQ0FB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 +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaWVudHMvY29uc3RhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLGdEQUF3QjtBQUl4QixtREFBaUM7QUFFakM7Ozs7O0dBS0c7QUFFSCxXQUFXO0FBQ0UsUUFBQSxZQUFZLEdBQUcsc0JBQXNCLENBQUM7QUFDdEMsUUFBQSxnQkFBZ0IsR0FBRyxzQkFBc0IsQ0FBQztBQUMxQyxRQUFBLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO0FBQ3BDLFFBQUEsY0FBYyxHQUFHLG1CQUFtQixDQUFDO0FBQ2xELDJDQUEyQztBQUM5QixRQUFBLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO0FBRWpELHFDQUFxQztBQUNyQyxJQUFZLGNBTVg7QUFORCxXQUFZLGNBQWM7SUFDeEIsc0VBQW9ELENBQUE7SUFDcEQsc0VBQW9ELENBQUE7SUFDcEQsaURBQStCLENBQUE7SUFDL0IsMkNBQTJDO0lBQzNDLHdEQUFzQyxDQUFBO0FBQ3hDLENBQUMsRUFOVyxjQUFjLEdBQWQsc0JBQWMsS0FBZCxzQkFBYyxRQU16QjtBQUVELElBQVksYUFNWDtBQU5ELFdBQVksYUFBYTtJQUN2Qix3RUFBdUQsQ0FBQTtJQUN2RCx3RUFBdUQsQ0FBQTtJQUN2RCw4Q0FBNkIsQ0FBQTtJQUM3QiwyQ0FBMkM7SUFDM0MsMkRBQTBDLENBQUE7QUFDNUMsQ0FBQyxFQU5XLGFBQWEsR0FBYixxQkFBYSxLQUFiLHFCQUFhLFFBTXhCO0FBRUQsSUFBWSxhQUVYO0FBRkQsV0FBWSxhQUFhO0lBQ3ZCLG1FQUFrRCxDQUFBO0FBQ3BELENBQUMsRUFGVyxhQUFhLEdBQWIscUJBQWEsS0FBYixxQkFBYSxRQUV4QjtBQUVELElBQVksZ0JBTVg7QUFORCxXQUFZLGdCQUFnQjtJQUMxQixtRUFBK0MsQ0FBQTtJQUMvQyx5RUFBcUQsQ0FBQTtJQUNyRCxvREFBZ0MsQ0FBQTtJQUNoQywyQ0FBMkM7SUFDM0Msc0VBQWtELENBQUE7QUFDcEQsQ0FBQyxFQU5XLGdCQUFnQixHQUFoQix3QkFBZ0IsS0FBaEIsd0JBQWdCLFFBTTNCO0FBRUQsd0NBQXdDO0FBRXhDLElBQVksU0FJWDtBQUpELFdBQVksU0FBUztJQUNuQix1Q0FBMEIsQ0FBQTtJQUMxQiwyQ0FBMkM7SUFDM0MsdUNBQTBCLENBQUE7QUFDNUIsQ0FBQyxFQUpXLFNBQVMsR0FBVCxpQkFBUyxLQUFULGlCQUFTLFFBSXBCO0FBQ1ksUUFBQSxrQkFBa0IsR0FBVyxzQkFBc0IsQ0FBQztBQUNqRSwyQ0FBMkM7QUFDOUIsUUFBQSxrQkFBa0IsR0FBVyxnQkFBZ0IsQ0FBQztBQUUzRCx1Q0FBdUM7QUFDdkMsSUFBWSxnQkFHWDtBQUhELFdBQVksZ0JBQWdCO0lBQzFCLHFDQUFpQixDQUFBO0lBQ2pCLGlDQUFhLENBQUE7QUFDZixDQUFDLEVBSFcsZ0JBQWdCLEdBQWhCLHdCQUFnQixLQUFoQix3QkFBZ0IsUUFHM0I7QUFFRCx5Q0FBeUM7QUFDekMsb0JBQW9CO0FBQ3BCLFNBQVM7QUFDSSxRQUFBLGlCQUFpQixHQUFHLDhCQUE4QixDQUFDO0FBRWhFLFFBQVE7QUFDSyxRQUFBLDRCQUE0QixHQUFHLGtDQUFrQyxDQUFDO0FBRS9FLGdCQUFnQjtBQUNoQixTQUFTO0FBQ0ksUUFBQSx3QkFBd0IsR0FBRyxrQ0FBa0MsQ0FBQztBQUM5RCxRQUFBLHlCQUF5QixHQUFHLG1DQUFtQyxDQUFDO0FBQ2hFLFFBQUEscUJBQXFCLEdBQUcsbUNBQW1DLENBQUM7QUFDNUQsUUFBQSw2QkFBNkIsR0FBRyxzQ0FBc0MsQ0FBQztBQUN2RSxRQUFBLDZCQUE2QixHQUFHLHNDQUFzQyxDQUFDO0FBRXBGLGFBQWE7QUFDQSxRQUFBLDBCQUEwQixHQUFHLHdDQUF3QyxDQUFDO0FBRW5GLFlBQVk7QUFDQyxRQUFBLHlDQUF5QyxHQUNwRCxxREFBcUQsQ0FBQztBQUV4RCxlQUFlO0FBQ0YsUUFBQSw2QkFBNkIsR0FBRyw2Q0FBNkMsQ0FBQztBQUUzRixXQUFXO0FBQ0UsUUFBQSxpQ0FBaUMsR0FBRyw0Q0FBNEMsQ0FBQztBQUU5RixZQUFZO0FBQ0MsUUFBQSw0QkFBNEIsR0FBRyx5Q0FBeUMsQ0FBQztBQUN6RSxRQUFBLHFDQUFxQyxHQUNoRCxpREFBaUQsQ0FBQztBQUN2QyxRQUFBLGtDQUFrQyxHQUFHLDhDQUE4QyxDQUFDO0FBRWpHLGVBQWU7QUFDRixRQUFBLCtCQUErQixHQUFHLCtDQUErQyxDQUFDO0FBRS9GLFVBQVU7QUFDRyxRQUFBLGlDQUFpQyxHQUFHLDJDQUEyQyxDQUFDO0FBQ2hGLFFBQUEsb0NBQW9DLEdBQUcsOENBQThDLENBQUM7QUFFbkcsWUFBWTtBQUNDLFFBQUEscUJBQXFCLEdBQUcscUNBQXFDLENBQUM7QUFDOUQsUUFBQSx1QkFBdUIsR0FBRyx1Q0FBdUMsQ0FBQztBQUUvRSxpQkFBaUI7QUFDSixRQUFBLHNDQUFzQyxHQUNqRCx5REFBeUQsQ0FBQztBQUU1RCw0Q0FBNEM7QUFDNUMsa0VBQWtFO0FBQ3JELFFBQUEsa0JBQWtCLEdBQUcsNkNBQTZDLENBQUM7QUFDbkUsUUFBQSx1QkFBdUIsR0FBRyw2Q0FBNkMsQ0FBQztBQUN4RSxRQUFBLHdCQUF3QixHQUFHLDZDQUE2QyxDQUFDO0FBRXRGLHVEQUF1RDtBQUN2RCxJQUFZLGtCQUlYO0FBSkQsV0FBWSxrQkFBa0I7SUFDNUIsK0JBQVMsQ0FBQTtJQUNULGlDQUFXLENBQUE7SUFDWCxtQ0FBYSxDQUFBO0FBQ2YsQ0FBQyxFQUpXLGtCQUFrQixHQUFsQiwwQkFBa0IsS0FBbEIsMEJBQWtCLFFBSTdCO0FBRUQsd0NBQXdDO0FBQ3hDLHdDQUF3QztBQUN4QyxJQUFZLFNBT1g7QUFQRCxXQUFZLFNBQVM7SUFDbkIsNEJBQWUsQ0FBQTtJQUNmLDhCQUFpQixDQUFBO0lBQ2pCLHNDQUF5QixDQUFBO0lBQ3pCLDhDQUFpQyxDQUFBO0lBQ2pDLHdDQUEyQixDQUFBO0lBQzNCLHNEQUF5QyxDQUFBO0FBQzNDLENBQUMsRUFQVyxTQUFTLEdBQVQsaUJBQVMsS0FBVCxpQkFBUyxRQU9wQjtBQUVELHVDQUF1QztBQUN2Qyx3Q0FBd0M7QUFDeEMsSUFBWSxTQUdYO0FBSEQsV0FBWSxTQUFTO0lBQ25CLHdCQUFXLENBQUE7SUFDWCwwQkFBYSxDQUFBO0FBQ2YsQ0FBQyxFQUhXLFNBQVMsR0FBVCxpQkFBUyxLQUFULGlCQUFTLFFBR3BCO0FBRUQsOENBQThDO0FBQzlDLCtDQUErQztBQUMvQyxJQUFZLGdCQUlYO0FBSkQsV0FBWSxnQkFBZ0I7SUFDMUIsK0JBQVcsQ0FBQTtJQUNYLCtCQUFXLENBQUE7SUFDWCwrQkFBVyxDQUFBO0FBQ2IsQ0FBQyxFQUpXLGdCQUFnQixHQUFoQix3QkFBZ0IsS0FBaEIsd0JBQWdCLFFBSTNCO0FBRUQsNENBQTRDO0FBQzVDLDZDQUE2QztBQUM3QyxJQUFZLGNBS1g7QUFMRCxXQUFZLGNBQWM7SUFDeEIscUNBQW1CLENBQUE7SUFDbkIsNkJBQVcsQ0FBQTtJQUNYLDZCQUFXLENBQUE7SUFDWCx5Q0FBdUIsQ0FBQTtBQUN6QixDQUFDLEVBTFcsY0FBYyxHQUFkLHNCQUFjLEtBQWQsc0JBQWMsUUFLekI7QUFFRCx5Q0FBeUM7QUFDekMsMENBQTBDO0FBQzFDLElBQVksV0FNWDtBQU5ELFdBQVksV0FBVztJQUNyQix3REFBeUMsQ0FBQTtJQUN6Qyw0QkFBYSxDQUFBO0lBQ2IsZ0NBQWlCLENBQUE7SUFDakIsNERBQTZDLENBQUE7SUFDN0Msb0NBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQU5XLFdBQVcsR0FBWCxtQkFBVyxLQUFYLG1CQUFXLFFBTXRCO0FBRUQsSUFBWSxVQUVYO0FBRkQsV0FBWSxVQUFVO0lBQ3BCLHFDQUF1QixDQUFBO0FBQ3pCLENBQUMsRUFGVyxVQUFVLEdBQVYsa0JBQVUsS0FBVixrQkFBVSxRQUVyQjtBQUVELElBQVksY0FJWDtBQUpELFdBQVksY0FBYztJQUN4QiwrQkFBYSxDQUFBO0lBQ2IsbUNBQWlCLENBQUE7SUFDakIsMkNBQXlCLENBQUE7QUFDM0IsQ0FBQyxFQUpXLGNBQWMsR0FBZCxzQkFBYyxLQUFkLHNCQUFjLFFBSXpCO0FBRUQsdURBQXVEO0FBRXZELElBQVksVUFHWDtBQUhELFdBQVksVUFBVTtJQUNwQixpQ0FBbUIsQ0FBQTtJQUNuQix1Q0FBeUIsQ0FBQTtBQUMzQixDQUFDLEVBSFcsVUFBVSxHQUFWLGtCQUFVLEtBQVYsa0JBQVUsUUFHckI7QUFFRCxJQUFZLGVBR1g7QUFIRCxXQUFZLGVBQWU7SUFDekIsZ0NBQWEsQ0FBQTtJQUNiLDhCQUFXLENBQUE7QUFDYixDQUFDLEVBSFcsZUFBZSxHQUFmLHVCQUFlLEtBQWYsdUJBQWUsUUFHMUI7QUFFRCxJQUFZLDhCQUlYO0FBSkQsV0FBWSw4QkFBOEI7SUFDeEMsaURBQWUsQ0FBQTtJQUNmLG1EQUFpQixDQUFBO0lBQ2pCLHFEQUFtQixDQUFBO0FBQ3JCLENBQUMsRUFKVyw4QkFBOEIsR0FBOUIsc0NBQThCLEtBQTlCLHNDQUE4QixRQUl6QztBQUVELHlDQUF5QztBQUM1QixRQUFBLG1CQUFtQixHQUFXLElBQUssQ0FBQztBQUVwQyxRQUFBLG1CQUFtQixHQUFXLEdBQUcsQ0FBQztBQUVsQyxRQUFBLGtCQUFrQixHQUFXLEVBQUUsQ0FBQztBQUVoQyxRQUFBLG1CQUFtQixHQUFXLENBQUMsQ0FBQztBQUU3QyxXQUFXO0FBQ0UsUUFBQSxZQUFZLEdBQWdCO0lBQ3ZDLEdBQUcsRUFBRSxJQUFJLFVBQVUsRUFBRTtJQUNyQixNQUFNLEVBQUUsY0FBSSxDQUFDLEtBQUs7SUFDbEIsS0FBSyxFQUFFLGNBQUksQ0FBQyxrQkFBa0I7SUFDOUIsVUFBVSxFQUFFLElBQUk7SUFDaEIsT0FBTyxFQUFFLEtBQUs7Q0FDZixDQUFDO0FBRUYsTUFBYSxhQUFhO0lBSXhCLFlBQVksWUFBb0IsRUFBRSxpQkFBeUI7UUFDekQsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDakMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGlCQUFpQixDQUFDO0lBQzdDLENBQUM7Q0FDRjtBQVJELHNDQVFDO0FBRUQsTUFBYSxlQUFlO0lBUTFCLFlBQ0UsWUFBb0IsRUFDcEIsT0FBZSxFQUNmLE1BQW1CLEVBQ25CLGdCQUFtQyxFQUNuQyxpQkFBMEIsRUFDMUIsaUJBQTJCO1FBRTNCLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUM7UUFDM0YsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO1FBQ3pDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztRQUMzQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsaUJBQWlCLENBQUM7SUFDN0MsQ0FBQztDQUNGO0FBeEJELDBDQXdCQztBQUVELE1BQWEsT0FBTztJQUNsQixZQUNTLEdBQVcsRUFDWCxhQUE0QixFQUM1QixlQUFnQztRQUZoQyxRQUFHLEdBQUgsR0FBRyxDQUFRO1FBQ1gsa0JBQWEsR0FBYixhQUFhLENBQWU7UUFDNUIsb0JBQWUsR0FBZixlQUFlLENBQWlCO0lBQ3RDLENBQUM7SUFFSixNQUFNLENBQUMsT0FBTztRQUNaLE1BQU0sYUFBYSxHQUFHLElBQUksYUFBYSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZGLE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUN6QyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQ3hCLHdCQUFnQixFQUNoQjtZQUNFLGdCQUFnQixFQUFFLFNBQVM7WUFDM0IsVUFBVSxFQUFFLHNFQUFzRTtZQUNsRixjQUFjLEVBQUUsT0FBTztZQUN2QixhQUFhLEVBQUUsQ0FBQztZQUNoQixtQkFBbUIsRUFBRSxFQUFFO1NBQ3hCLEVBQ0QsU0FBUyxFQUNULGdCQUFnQixDQUNqQixDQUFDO1FBQ0YsT0FBTyxJQUFJLE9BQU8sQ0FBQyxTQUFTLEVBQUUsYUFBYSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRCxNQUFNLENBQUMsT0FBTztRQUNaLE1BQU0sYUFBYSxHQUFHLElBQUksYUFBYSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZGLE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUN6QyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQ3hCLHdCQUFnQixFQUNoQjtZQUNFLGdCQUFnQixFQUFFLFNBQVM7WUFDM0IsVUFBVSxFQUFFLHNFQUFzRTtZQUNsRixjQUFjLEVBQUUsT0FBTztZQUN2QixhQUFhLEVBQUUsQ0FBQztZQUNoQixtQkFBbUIsRUFBRSxFQUFFO1NBQ3hCLEVBQ0QsU0FBUyxFQUNULGdCQUFnQixDQUNqQixDQUFDO1FBQ0YsT0FBTyxJQUFJLE9BQU8sQ0FBQyxTQUFTLEVBQUUsYUFBYSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSztRQUNWLE1BQU0sYUFBYSxHQUFHLElBQUksYUFBYSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25GLE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUN6QyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQ3RCLHNCQUFjLEVBQ2Q7WUFDRSxnQkFBZ0IsRUFBRSxTQUFTO1lBQzNCLFVBQVUsRUFBRSxzRUFBc0U7WUFDbEYsY0FBYyxFQUFFLE9BQU87WUFDdkIsYUFBYSxFQUFFLENBQUM7WUFDaEIsbUJBQW1CLEVBQUUsRUFBRTtTQUN4QixFQUNELFNBQVMsRUFDVCxnQkFBZ0IsQ0FDakIsQ0FBQztRQUNGLE9BQU8sSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQsNENBQTRDO0lBQzVDLE1BQU0sQ0FBQyxPQUFPO1FBQ1osTUFBTSxhQUFhLEdBQUcsSUFBSSxhQUFhLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdkYsTUFBTSxlQUFlLEdBQUcsSUFBSSxlQUFlLENBQ3pDLGdCQUFnQixDQUFDLE9BQU8sRUFDeEIsd0JBQWdCLEVBQ2hCO1lBQ0UsZ0JBQWdCLEVBQUUsT0FBTztZQUN6QixVQUFVLEVBQUUsc0VBQXNFO1lBQ2xGLGNBQWMsRUFBRSxPQUFPO1lBQ3ZCLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLG1CQUFtQixFQUFFLEVBQUU7U0FDeEIsRUFDRCxTQUFTLEVBQ1QsZ0JBQWdCLENBQ2pCLENBQUM7UUFDRixPQUFPLElBQUksT0FBTyxDQUFDLFNBQVMsRUFBRSxhQUFhLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELFNBQVM7UUFDUCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEIsQ0FBQztDQUNGO0FBbkZELDBCQW1GQyJ9 /***/ }), @@ -208170,6 +208176,7 @@ const rest_1 = __importDefault(__webpack_require__(/*! ./rest */ "./src/clients/ * @description REST endpoints for data related to a particular address. */ class AccountClient extends rest_1.default { + // ------ Subaccount ------ // async getSubaccounts(address, limit) { const uri = `/v4/addresses/${address}`; return this.get(uri, { limit }); @@ -208178,6 +208185,11 @@ class AccountClient extends rest_1.default { const uri = `/v4/addresses/${address}/subaccountNumber/${subaccountNumber}`; return this.get(uri); } + async getParentSubaccount(address, parentSubaccountNumber) { + const uri = `/v4/addresses/${address}/subaccountNumber/${parentSubaccountNumber}`; + return this.get(uri); + } + // ------ Positions ------ // async getSubaccountPerpetualPositions(address, subaccountNumber, status, limit, createdBeforeOrAtHeight, createdBeforeOrAt) { const uri = '/v4/perpetualPositions'; return this.get(uri, { @@ -208200,6 +208212,18 @@ class AccountClient extends rest_1.default { createdBeforeOrAt, }); } + // ------ Transfers ------ // + async getTransfersBetween(sourceAddress, sourceSubaccountNumber, recipientAddress, recipientSubaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt) { + const uri = '/v4/transfers/between'; + return this.get(uri, { + sourceAddress, + sourceSubaccountNumber, + recipientAddress, + recipientSubaccountNumber, + createdBeforeOrAtHeight, + createdBeforeOrAt, + }); + } async getSubaccountTransfers(address, subaccountNumber, limit, createdBeforeOrAtHeight, createdBeforeOrAt, page) { const uri = '/v4/transfers'; return this.get(uri, { @@ -208222,6 +208246,7 @@ class AccountClient extends rest_1.default { page, }); } + // ------ Orders ------ // async getSubaccountOrders(address, subaccountNumber, ticker, tickerType = constants_1.TickerType.PERPETUAL, side, status, type, limit, goodTilBlockBeforeOrAt, goodTilBlockTimeBeforeOrAt, returnLatestOrders) { const uri = '/v4/orders'; return this.get(uri, { @@ -208238,10 +208263,26 @@ class AccountClient extends rest_1.default { returnLatestOrders, }); } + async getParentSubaccountNumberOrders(address, parentSubaccountNumber, ticker, side, status, type, limit, goodTilBlockBeforeOrAt, goodTilBlockTimeBeforeOrAt, returnLatestOrders) { + const uri = '/v4/orders/parentSubaccountNumber'; + return this.get(uri, { + address, + parentSubaccountNumber, + ticker, + side, + status, + type, + limit, + goodTilBlockBeforeOrAt, + goodTilBlockTimeBeforeOrAt, + returnLatestOrders, + }); + } async getOrder(orderId) { const uri = `/v4/orders/${orderId}`; return this.get(uri); } + // ------ Fills ------ // async getSubaccountFills(address, subaccountNumber, ticker, tickerType = constants_1.TickerType.PERPETUAL, limit, createdBeforeOrAtHeight, createdBeforeOrAt, page) { const uri = '/v4/fills'; return this.get(uri, { @@ -208268,6 +208309,7 @@ class AccountClient extends rest_1.default { page, }); } + // ------ Pnl ------ // async getSubaccountHistoricalPNLs(address, subaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt, createdOnOrAfterHeight, createdOnOrAfter, limit, page) { const uri = '/v4/historical-pnl'; return this.get(uri, { @@ -208281,20 +208323,27 @@ class AccountClient extends rest_1.default { page, }); } - async getTransfersBetween(sourceAddress, sourceSubaccountNumber, recipientAddress, recipientSubaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt) { - const uri = '/v4/transfers/between'; + async getParentSubaccountNumberHistoricalPNLs(address, parentSubaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt, createdOnOrAfterHeight, createdOnOrAfter, limit, page) { + const uri = '/v4//historical-pnl/parentSubaccount'; return this.get(uri, { - sourceAddress, - sourceSubaccountNumber, - recipientAddress, - recipientSubaccountNumber, + address, + parentSubaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt, + createdOnOrAfterHeight, + createdOnOrAfter, + limit, + page, }); } + // ------ Rewards ------ // + async getHistoricalTradingRewardsAggregations(address, period, limit, startingBeforeOrAt, startingBeforeOrAtHeight) { + const uri = `/v4/historicalTradingRewardAggregations/${address}`; + return this.get(uri, { period, limit, startingBeforeOrAt, startingBeforeOrAtHeight }); + } } exports["default"] = AccountClient; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3VudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jbGllbnRzL21vZHVsZXMvYWNjb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDRDQUE2RjtBQUU3RixrREFBZ0M7QUFFaEM7O0dBRUc7QUFDSCxNQUFxQixhQUFjLFNBQVEsY0FBVTtJQUNuRCxLQUFLLENBQUMsY0FBYyxDQUFDLE9BQWUsRUFBRSxLQUFjO1FBQ2xELE1BQU0sR0FBRyxHQUFHLGlCQUFpQixPQUFPLEVBQUUsQ0FBQztRQUN2QyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFlLEVBQUUsZ0JBQXdCO1FBQzNELE1BQU0sR0FBRyxHQUFHLGlCQUFpQixPQUFPLHFCQUFxQixnQkFBZ0IsRUFBRSxDQUFDO1FBQzVFLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBRUQsS0FBSyxDQUFDLCtCQUErQixDQUNuQyxPQUFlLEVBQ2YsZ0JBQXdCLEVBQ3hCLE1BQThCLEVBQzlCLEtBQXFCLEVBQ3JCLHVCQUF1QyxFQUN2QyxpQkFBaUM7UUFFakMsTUFBTSxHQUFHLEdBQUcsd0JBQXdCLENBQUM7UUFDckMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtZQUNuQixPQUFPO1lBQ1AsZ0JBQWdCO1lBQ2hCLE1BQU07WUFDTixLQUFLO1lBQ0wsdUJBQXVCO1lBQ3ZCLGlCQUFpQjtTQUNsQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsS0FBSyxDQUFDLDJCQUEyQixDQUMvQixPQUFlLEVBQ2YsZ0JBQXdCLEVBQ3hCLE1BQThCLEVBQzlCLEtBQXFCLEVBQ3JCLHVCQUF1QyxFQUN2QyxpQkFBaUM7UUFFakMsTUFBTSxHQUFHLEdBQUcsb0JBQW9C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 +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3VudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jbGllbnRzL21vZHVsZXMvYWNjb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDRDQU9zQjtBQUV0QixrREFBZ0M7QUFFaEM7O0dBRUc7QUFDSCxNQUFxQixhQUFjLFNBQVEsY0FBVTtJQUNuRCw4QkFBOEI7SUFFOUIsS0FBSyxDQUFDLGNBQWMsQ0FBQyxPQUFlLEVBQUUsS0FBYztRQUNsRCxNQUFNLEdBQUcsR0FBRyxpQkFBaUIsT0FBTyxFQUFFLENBQUM7UUFDdkMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBZSxFQUFFLGdCQUF3QjtRQUMzRCxNQUFNLEdBQUcsR0FBRyxpQkFBaUIsT0FBTyxxQkFBcUIsZ0JBQWdCLEVBQUUsQ0FBQztRQUM1RSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdkIsQ0FBQztJQUVELEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxPQUFlLEVBQUUsc0JBQThCO1FBQ3ZFLE1BQU0sR0FBRyxHQUFHLGlCQUFpQixPQUFPLHFCQUFxQixzQkFBc0IsRUFBRSxDQUFDO1FBQ2xGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBRUQsNkJBQTZCO0lBRTdCLEtBQUssQ0FBQywrQkFBK0IsQ0FDbkMsT0FBZSxFQUNmLGdCQUF3QixFQUN4QixNQUE4QixFQUM5QixLQUFxQixFQUNyQix1QkFBdUMsRUFDdkMsaUJBQWlDO1FBRWpDLE1BQU0sR0FBRyxHQUFHLHdCQUF3QixDQUFDO1FBQ3JDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7WUFDbkIsT0FBTztZQUNQLGdCQUFnQjtZQUNoQixNQUFN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 /***/ }), diff --git a/v4-client-js/package-lock.json b/v4-client-js/package-lock.json index 17b9e2ce..7c446c36 100644 --- a/v4-client-js/package-lock.json +++ b/v4-client-js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dydxprotocol/v4-client-js", - "version": "1.3.15", + "version": "1.3.16", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/v4-client-js/package.json b/v4-client-js/package.json index efacf1e4..16b73aac 100644 --- a/v4-client-js/package.json +++ b/v4-client-js/package.json @@ -1,6 +1,6 @@ { "name": "@dydxprotocol/v4-client-js", - "version": "1.3.15", + "version": "1.3.16", "description": "General client library for the new dYdX system (v4 decentralized)", "main": "build/src/index.js", "scripts": { diff --git a/v4-client-js/src/clients/constants.ts b/v4-client-js/src/clients/constants.ts index 694ba123..297e85a6 100644 --- a/v4-client-js/src/clients/constants.ts +++ b/v4-client-js/src/clients/constants.ts @@ -86,7 +86,8 @@ export const TYPE_URL_MSG_UPDATE_CLOB_PAIR = '/dydxprotocol.clob.MsgUpdateClobPa export const TYPE_URL_MSG_DELAY_MESSAGE = '/dydxprotocol.delaymsg.MsgDelayMessage'; // x/listing -export const TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS = '/dydxprotocol.listing.MsgCreateMarketPermissionless'; +export const TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS = + '/dydxprotocol.listing.MsgCreateMarketPermissionless'; // x/perpetuals export const TYPE_URL_MSG_CREATE_PERPETUAL = '/dydxprotocol.perpetuals.MsgCreatePerpetual'; @@ -195,6 +196,12 @@ export enum PnlTickInterval { day = 'day', } +export enum TradingRewardAggregationPeriod { + DAILY = 'DAILY', + WEEKLY = 'WEEKLY', + MONTHLY = 'MONTHLY', +} + // ------------ API Defaults ------------ export const DEFAULT_API_TIMEOUT: number = 3_000; diff --git a/v4-client-js/src/clients/modules/account.ts b/v4-client-js/src/clients/modules/account.ts index 19bdd422..e9521ba9 100644 --- a/v4-client-js/src/clients/modules/account.ts +++ b/v4-client-js/src/clients/modules/account.ts @@ -1,4 +1,11 @@ -import { OrderSide, OrderStatus, OrderType, PositionStatus, TickerType } from '../constants'; +import { + OrderSide, + OrderStatus, + OrderType, + PositionStatus, + TickerType, + TradingRewardAggregationPeriod, +} from '../constants'; import { Data } from '../types'; import RestClient from './rest'; @@ -6,6 +13,8 @@ import RestClient from './rest'; * @description REST endpoints for data related to a particular address. */ export default class AccountClient extends RestClient { + // ------ Subaccount ------ // + async getSubaccounts(address: string, limit?: number): Promise { const uri = `/v4/addresses/${address}`; return this.get(uri, { limit }); @@ -16,6 +25,13 @@ export default class AccountClient extends RestClient { return this.get(uri); } + async getParentSubaccount(address: string, parentSubaccountNumber: number): Promise { + const uri = `/v4/addresses/${address}/subaccountNumber/${parentSubaccountNumber}`; + return this.get(uri); + } + + // ------ Positions ------ // + async getSubaccountPerpetualPositions( address: string, subaccountNumber: number, @@ -54,6 +70,27 @@ export default class AccountClient extends RestClient { }); } + // ------ Transfers ------ // + + async getTransfersBetween( + sourceAddress: string, + sourceSubaccountNumber: string, + recipientAddress: string, + recipientSubaccountNumber: string, + createdBeforeOrAtHeight?: number | null, + createdBeforeOrAt?: string | null, + ): Promise { + const uri = '/v4/transfers/between'; + return this.get(uri, { + sourceAddress, + sourceSubaccountNumber, + recipientAddress, + recipientSubaccountNumber, + createdBeforeOrAtHeight, + createdBeforeOrAt, + }); + } + async getSubaccountTransfers( address: string, subaccountNumber: number, @@ -92,6 +129,8 @@ export default class AccountClient extends RestClient { }); } + // ------ Orders ------ // + async getSubaccountOrders( address: string, subaccountNumber: number, @@ -121,11 +160,40 @@ export default class AccountClient extends RestClient { }); } + async getParentSubaccountNumberOrders( + address: string, + parentSubaccountNumber: number, + ticker?: string | null, + side?: OrderSide | null, + status?: OrderStatus | null, + type?: OrderType | null, + limit?: number | null, + goodTilBlockBeforeOrAt?: number | null, + goodTilBlockTimeBeforeOrAt?: string | null, + returnLatestOrders?: boolean | null, + ): Promise { + const uri = '/v4/orders/parentSubaccountNumber'; + return this.get(uri, { + address, + parentSubaccountNumber, + ticker, + side, + status, + type, + limit, + goodTilBlockBeforeOrAt, + goodTilBlockTimeBeforeOrAt, + returnLatestOrders, + }); + } + async getOrder(orderId: string): Promise { const uri = `/v4/orders/${orderId}`; return this.get(uri); } + // ------ Fills ------ // + async getSubaccountFills( address: string, subaccountNumber: number, @@ -172,6 +240,8 @@ export default class AccountClient extends RestClient { }); } + // ------ Pnl ------ // + async getSubaccountHistoricalPNLs( address: string, subaccountNumber: number, @@ -195,22 +265,39 @@ export default class AccountClient extends RestClient { }); } - async getTransfersBetween( - sourceAddress: string, - sourceSubaccountNumber: string, - recipientAddress: string, - recipientSubaccountNumber: string, + async getParentSubaccountNumberHistoricalPNLs( + address: string, + parentSubaccountNumber: number, createdBeforeOrAtHeight?: number | null, - createdBeforeOrAt?: string | null - ): Promise { - const uri = '/v4/transfers/between'; + createdBeforeOrAt?: string | null, + createdOnOrAfterHeight?: number | null, + createdOnOrAfter?: string | null, + limit?: number | null, + page?: number | null, + ): Promise { + const uri = '/v4//historical-pnl/parentSubaccount'; return this.get(uri, { - sourceAddress, - sourceSubaccountNumber, - recipientAddress, - recipientSubaccountNumber, + address, + parentSubaccountNumber, createdBeforeOrAtHeight, createdBeforeOrAt, + createdOnOrAfterHeight, + createdOnOrAfter, + limit, + page, }); } + + // ------ Rewards ------ // + + async getHistoricalTradingRewardsAggregations( + address: string, + period: TradingRewardAggregationPeriod, + limit?: number, + startingBeforeOrAt?: string, + startingBeforeOrAtHeight?: string, + ): Promise { + const uri = `/v4/historicalTradingRewardAggregations/${address}`; + return this.get(uri, { period, limit, startingBeforeOrAt, startingBeforeOrAtHeight }); + } } From 1327f57d22298b6831eaa592215fa24ee598899d Mon Sep 17 00:00:00 2001 From: tyleroooo Date: Fri, 6 Dec 2024 13:16:33 -0500 Subject: [PATCH 2/8] fix: add historical block trading reward endpoint (#303) --- v4-client-js/src/clients/modules/account.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/v4-client-js/src/clients/modules/account.ts b/v4-client-js/src/clients/modules/account.ts index e9521ba9..e4e0c37c 100644 --- a/v4-client-js/src/clients/modules/account.ts +++ b/v4-client-js/src/clients/modules/account.ts @@ -300,4 +300,14 @@ export default class AccountClient extends RestClient { const uri = `/v4/historicalTradingRewardAggregations/${address}`; return this.get(uri, { period, limit, startingBeforeOrAt, startingBeforeOrAtHeight }); } + + async getHistoricalBlockTradingRewards( + address: string, + limit?: number, + startingBeforeOrAt?: string, + startingBeforeOrAtHeight?: string, + ): Promise { + const uri = `/v4/historicalBlockTradingRewards/${address}`; + return this.get(uri, { limit, startingBeforeOrAt, startingBeforeOrAtHeight }); + } } From 976a5e34d681b9f535b301a53db68e4fceb62656 Mon Sep 17 00:00:00 2001 From: v0-e <134806759+v0-e@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:08:16 +0000 Subject: [PATCH 3/8] feat: Create market permissionless (#304) Adds an option to create a market permissionless. Closes #298. --- v4-client-rs/client/src/node/client/mod.rs | 28 ++++++++++++++++++++-- v4-client-rs/client/tests/test_node.rs | 24 ++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/v4-client-rs/client/src/node/client/mod.rs b/v4-client-rs/client/src/node/client/mod.rs index 79426102..10410c23 100644 --- a/v4-client-rs/client/src/node/client/mod.rs +++ b/v4-client-rs/client/src/node/client/mod.rs @@ -7,7 +7,9 @@ use super::{ }; use megavault::MegaVault; -pub use crate::indexer::{Address, ClientId, Height, OrderFlags, Subaccount, Tokenized, Usdc}; +pub use crate::indexer::{ + Address, ClientId, Height, OrderFlags, Subaccount, Ticker, Tokenized, Usdc, +}; use anyhow::{anyhow as err, Error, Result}; use bigdecimal::{ num_bigint::{BigInt, Sign}, @@ -38,12 +40,13 @@ use dydx_proto::{ Order, OrderBatch, }, feetiers::query_client::QueryClient as FeeTiersClient, + listing::MsgCreateMarketPermissionless, perpetuals::query_client::QueryClient as PerpetualsClient, prices::query_client::QueryClient as PricesClient, rewards::query_client::QueryClient as RewardsClient, sending::{MsgCreateTransfer, MsgDepositToSubaccount, MsgWithdrawFromSubaccount, Transfer}, stats::query_client::QueryClient as StatsClient, - subaccounts::query_client::QueryClient as SubaccountsClient, + subaccounts::{query_client::QueryClient as SubaccountsClient, SubaccountId}, vault::query_client::QueryClient as VaultClient, }, ToAny, @@ -511,6 +514,27 @@ impl NodeClient { MegaVault::new(self) } + /// Create a market permissionless + pub async fn create_market_permissionless( + &mut self, + account: &mut Account, + ticker: &Ticker, + subaccount: &Subaccount, + ) -> Result { + let subaccount_id = SubaccountId { + owner: subaccount.address.to_string(), + number: subaccount.number.0, + }; + let msg = MsgCreateMarketPermissionless { + ticker: ticker.to_string(), + subaccount_id: Some(subaccount_id), + }; + + let tx_raw = self.create_transaction(account, msg).await?; + + self.broadcast_transaction(tx_raw).await + } + /// Simulate a transaction. /// /// Check [the example](https://github.com/dydxprotocol/v4-clients/blob/main/v4-client-rs/client/examples/withdraw_other.rs). diff --git a/v4-client-rs/client/tests/test_node.rs b/v4-client-rs/client/tests/test_node.rs index b225a317..f52ef7d5 100644 --- a/v4-client-rs/client/tests/test_node.rs +++ b/v4-client-rs/client/tests/test_node.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow as err, Error}; use bigdecimal::{num_traits::cast::ToPrimitive, BigDecimal, One}; use chrono::{TimeDelta, Utc}; use dydx::{ - indexer::{OrderExecution, Token}, + indexer::{OrderExecution, Ticker, Token}, node::*, }; use dydx_proto::dydxprotocol::{ @@ -353,3 +353,25 @@ async fn test_node_close_position() -> Result<(), Error> { Ok(()) } + +#[tokio::test] +#[serial] +async fn test_node_create_market_permissionless() -> Result<(), Error> { + let env = TestEnv::testnet().await?; + let mut node = env.node; + let mut account = env.account; + + let subaccount = account.subaccount(0)?; + // Avoid creating a new market and just try to create one that already exists + let ticker = Ticker::from("ETH-USD"); + + let tx_res = node + .create_market_permissionless(&mut account, &ticker, &subaccount) + .await; + + match node.query_transaction_result(tx_res).await { + Err(e) if e.to_string().contains("Market params pair already exists") => Ok(()), + Err(e) => Err(e), + Ok(_) => Err(err!("Market creation (ETH-USD) should fail")), + } +} From aa0d95d298b2b202c4fe8a8160dd8f1b63b8f009 Mon Sep 17 00:00:00 2001 From: samtin0x <40127309+samtin0x@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:32:11 +0000 Subject: [PATCH 4/8] feat: add example for placing stop limit orders and update version (#290) --- .../dydx_v4_client/node/chain_helpers.py | 9 ++-- .../examples/stop_limit_order_example.py | 51 +++++++++++++++++++ v4-client-py-v2/pyproject.toml | 2 +- 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 v4-client-py-v2/examples/stop_limit_order_example.py diff --git a/v4-client-py-v2/dydx_v4_client/node/chain_helpers.py b/v4-client-py-v2/dydx_v4_client/node/chain_helpers.py index d415efb9..000f77b9 100644 --- a/v4-client-py-v2/dydx_v4_client/node/chain_helpers.py +++ b/v4-client-py-v2/dydx_v4_client/node/chain_helpers.py @@ -53,10 +53,13 @@ def calculate_client_metadata(order_type: OrderType) -> int: @staticmethod def calculate_condition_type(order_type: OrderType) -> Order.ConditionType: - if order_type in [OrderType.LIMIT, OrderType.MARKET, OrderType.STOP_MARKET]: + if order_type in [ + OrderType.LIMIT, + OrderType.MARKET, + OrderType.STOP_MARKET, + OrderType.STOP_LIMIT, + ]: return Order.ConditionType.CONDITION_TYPE_UNSPECIFIED - elif order_type in [OrderType.STOP_LIMIT]: - return Order.ConditionType.CONDITION_TYPE_STOP_LOSS elif order_type in [OrderType.TAKE_PROFIT_LIMIT, OrderType.TAKE_PROFIT_MARKET]: return Order.ConditionType.CONDITION_TYPE_TAKE_PROFIT else: diff --git a/v4-client-py-v2/examples/stop_limit_order_example.py b/v4-client-py-v2/examples/stop_limit_order_example.py new file mode 100644 index 00000000..08e53644 --- /dev/null +++ b/v4-client-py-v2/examples/stop_limit_order_example.py @@ -0,0 +1,51 @@ +import random + +from dydx_v4_client import MAX_CLIENT_ID, OrderFlags +from v4_proto.dydxprotocol.clob.order_pb2 import Order + +from dydx_v4_client.indexer.rest.constants import OrderType, OrderExecution +from dydx_v4_client.indexer.rest.indexer_client import IndexerClient +from dydx_v4_client.network import TESTNET +from dydx_v4_client.node.client import NodeClient +from dydx_v4_client.node.market import Market +from dydx_v4_client.wallet import Wallet +from tests.conftest import DYDX_TEST_MNEMONIC, TEST_ADDRESS + +MARKET_ID = "ETH-USD" + + +async def test_place_stop_limit_order(): + size, trigger_price = 0.001, 1800 + node = await NodeClient.connect(TESTNET.node) + indexer = IndexerClient(TESTNET.rest_indexer) + + market = Market( + (await indexer.markets.get_perpetual_markets(MARKET_ID))["markets"][MARKET_ID] + ) + wallet = await Wallet.from_mnemonic(node, DYDX_TEST_MNEMONIC, TEST_ADDRESS) + + order_id = market.order_id( + TEST_ADDRESS, 0, random.randint(0, MAX_CLIENT_ID), OrderFlags.SHORT_TERM + ) + + current_block = await node.latest_block_height() + print(current_block) + new_order = market.order( + order_id=order_id, + order_type=OrderType.STOP_LIMIT, + side=Order.Side.SIDE_SELL, + size=size, + price=trigger_price, + time_in_force=Order.TimeInForce.TIME_IN_FORCE_IOC, + reduce_only=False, + execution=OrderExecution.IOC, + good_til_block=current_block + 10, + ) + print(new_order) + transaction = await node.place_order( + wallet=wallet, + order=new_order, + ) + + print(transaction) + wallet.sequence += 1 diff --git a/v4-client-py-v2/pyproject.toml b/v4-client-py-v2/pyproject.toml index 9fd52079..ff6db3d0 100644 --- a/v4-client-py-v2/pyproject.toml +++ b/v4-client-py-v2/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dydx-v4-client" -version = "1.1.2" +version = "1.1.3" description = "" authors = [ "Saul Martin ", From ca0c244a8c081c327cb3561fc3257b14284c5ee0 Mon Sep 17 00:00:00 2001 From: v0-e <134806759+v0-e@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:02:43 +0000 Subject: [PATCH 5/8] chore(deps): Run cargo update/upgrade (#310) Updates dependencies. Only change required in our code is related with tungstenite's recent `Message` [changes](https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0260). --- v4-client-rs/Cargo.toml | 2 +- v4-client-rs/client/Cargo.toml | 6 +++--- v4-client-rs/client/src/indexer/sock/messages.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/v4-client-rs/Cargo.toml b/v4-client-rs/Cargo.toml index cb98e61c..1bffac2e 100644 --- a/v4-client-rs/Cargo.toml +++ b/v4-client-rs/Cargo.toml @@ -16,5 +16,5 @@ bigdecimal = { version = "0.4", features = ["serde"] } derive_more = { version = "1", features = ["full"] } log = "0.4" thiserror = "2" -tokio = { version = "1.41", features = ["fs", "rt-multi-thread"] } +tokio = { version = "1.42", features = ["fs", "rt-multi-thread"] } dydx-proto = "0.2.0" diff --git a/v4-client-rs/client/Cargo.toml b/v4-client-rs/client/Cargo.toml index ae318d17..cdbdcfe7 100644 --- a/v4-client-rs/client/Cargo.toml +++ b/v4-client-rs/client/Cargo.toml @@ -30,19 +30,19 @@ cosmrs = "0.21" chrono = { version = "0.4", features = ["serde"] } derive_more.workspace = true futures-util = "0.3" -governor = { version = "0.7", default-features = false, features = ["std"] } +governor = { version = "0.8", default-features = false, features = ["std"] } ibc-proto = { version = "0.51", optional = true } log.workspace = true rand = "0.8" reqwest = { version = "0.12", features = ["json"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -serde_with = "3.11" +serde_with = "3.12" strum = { version = "0.26", features = ["derive"] } thiserror.workspace = true tonic = { version = "0.12", features = ["tls-native-roots"] } tokio.workspace = true -tokio-tungstenite = { version = "0.24", features = ["native-tls"] } +tokio-tungstenite = { version = "0.26", features = ["native-tls"] } toml = "0.8" tower = { version = "0.5", features = ["timeout"] } dydx-proto.workspace = true diff --git a/v4-client-rs/client/src/indexer/sock/messages.rs b/v4-client-rs/client/src/indexer/sock/messages.rs index 219e6ec9..c7a4f78a 100644 --- a/v4-client-rs/client/src/indexer/sock/messages.rs +++ b/v4-client-rs/client/src/indexer/sock/messages.rs @@ -86,7 +86,7 @@ impl MessageFormatter { map.extend(fields); } } - Message::Text(message.to_string()) + Message::Text(message.to_string().into()) } } From 5efc587bcad4d23eec569bfab18802114d66784c Mon Sep 17 00:00:00 2001 From: Pawel Nowosielski Date: Wed, 22 Jan 2025 18:12:51 +0100 Subject: [PATCH 6/8] feat: replace crypto lib ecdsa with coincurve (#312) This PR replaces `ecdsa` with `coincurve` for crypto signing - `ecdsa`, being a pure Python implementation, is vulnerable to side-channel attacks - Ensured signature format aligns with expected canonical 64-bytes - All tests passing, maintaining functionality --------- Co-authored-by: ttl33 <19664986+ttl33@users.noreply.github.com> --- .../indexer/rest/noble_client.py | 34 ++-- v4-client-py-v2/dydx_v4_client/key_pair.py | 78 +++++++++ .../dydx_v4_client/node/builder.py | 7 +- v4-client-py-v2/dydx_v4_client/wallet.py | 36 +--- v4-client-py-v2/examples/basic_adder.py | 5 +- v4-client-py-v2/poetry.lock | 161 +++++++++++++++++- v4-client-py-v2/pyproject.toml | 4 +- v4-client-py-v2/tests/conftest.py | 23 ++- v4-client-py-v2/tests/test_crypto.py | 57 +++++++ .../tests/test_mutating_node_client.py | 4 +- 10 files changed, 338 insertions(+), 71 deletions(-) create mode 100644 v4-client-py-v2/dydx_v4_client/key_pair.py create mode 100644 v4-client-py-v2/tests/test_crypto.py diff --git a/v4-client-py-v2/dydx_v4_client/indexer/rest/noble_client.py b/v4-client-py-v2/dydx_v4_client/indexer/rest/noble_client.py index 714a151a..896fe746 100644 --- a/v4-client-py-v2/dydx_v4_client/indexer/rest/noble_client.py +++ b/v4-client-py-v2/dydx_v4_client/indexer/rest/noble_client.py @@ -1,7 +1,6 @@ from typing import List, Optional import grpc -from ecdsa.util import sigencode_string_canonize from v4_proto.cosmos.auth.v1beta1 import query_pb2_grpc as auth from v4_proto.cosmos.auth.v1beta1.auth_pb2 import BaseAccount from v4_proto.cosmos.auth.v1beta1.query_pb2 import QueryAccountRequest @@ -9,7 +8,6 @@ from v4_proto.cosmos.bank.v1beta1 import query_pb2_grpc as bank_query_grpc from v4_proto.cosmos.base.abci.v1beta1.abci_pb2 import TxResponse from v4_proto.cosmos.base.v1beta1.coin_pb2 import Coin -from v4_proto.cosmos.crypto.secp256k1.keys_pb2 import PubKey from v4_proto.cosmos.tx.signing.v1beta1.signing_pb2 import SignMode from v4_proto.cosmos.tx.v1beta1 import service_pb2_grpc from v4_proto.cosmos.tx.v1beta1.service_pb2 import ( @@ -29,7 +27,8 @@ from dydx_v4_client.config import GAS_MULTIPLIER from dydx_v4_client.node.builder import as_any -from dydx_v4_client.wallet import from_mnemonic +from dydx_v4_client.key_pair import KeyPair +from dydx_v4_client.wallet import Wallet class NobleClient: @@ -72,8 +71,8 @@ async def connect(self, mnemonic: str): """ if not mnemonic: raise ValueError("Mnemonic not provided") - private_key = from_mnemonic(mnemonic) - self.wallet = private_key + key_pair = KeyPair.from_mnemonic(mnemonic) + self.wallet = Wallet(key_pair, 0, 0) self.channel = grpc.secure_channel( self.rest_endpoint, grpc.ssl_channel_credentials(), @@ -178,26 +177,19 @@ async def send( # Sign and broadcast the transaction signer_info = SignerInfo( - public_key=as_any( - PubKey(key=self.wallet.get_verifying_key().to_string("compressed")) - ), + public_key=as_any(self.wallet.public_key), mode_info=ModeInfo(single=ModeInfo.Single(mode=SignMode.SIGN_MODE_DIRECT)), - sequence=self.get_account( - self.wallet.get_verifying_key().to_string() - ).sequence, + sequence=self.get_account(self.wallet.address).sequence, ) body = TxBody(messages=messages, memo=memo or self.default_client_memo) auth_info = AuthInfo(signer_infos=[signer_info], fee=fee) - signature = self.wallet.sign( + signature = self.wallet.key.sign( SignDoc( body_bytes=body.SerializeToString(), auth_info_bytes=auth_info.SerializeToString(), - account_number=self.get_account( - self.wallet.get_verifying_key().to_string() - ).account_number, + account_number=self.get_account(self.wallet.address).account_number, chain_id=self.chain_id, - ).SerializeToString(), - sigencode=sigencode_string_canonize, + ).SerializeToString() ) tx = Tx(body=body, auth_info=auth_info, signatures=[signature]) @@ -233,13 +225,9 @@ async def simulate_transaction( # Get simulated response signer_info = SignerInfo( - public_key=as_any( - PubKey(key=self.wallet.get_verifying_key().to_string("compressed")) - ), + public_key=as_any(self.wallet.public_key), mode_info=ModeInfo(single=ModeInfo.Single(mode=SignMode.SIGN_MODE_DIRECT)), - sequence=self.get_account( - self.wallet.get_verifying_key().to_string() - ).sequence, + sequence=self.get_account(self.wallet.address).sequence, ) body = TxBody(messages=messages, memo=memo or self.default_client_memo) auth_info = AuthInfo(signer_infos=[signer_info], fee=Fee(gas_limit=0)) diff --git a/v4-client-py-v2/dydx_v4_client/key_pair.py b/v4-client-py-v2/dydx_v4_client/key_pair.py new file mode 100644 index 00000000..c863ba4f --- /dev/null +++ b/v4-client-py-v2/dydx_v4_client/key_pair.py @@ -0,0 +1,78 @@ +""" +This module implements ECDSA (Elliptic Curve Digital Signature Algorithm) key pair wrapper class. Initially `ecdsa.SigningKey` was directly used. However due to security concerns and to avoid direct dependency on specific implementation, `KeyPair class was introduced. This class provides a wrapper around the `coincurve.PrivateKey` and mimics how `ecdsa` was used before. +""" + +from dataclasses import dataclass +from typing import Tuple + +from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins +from coincurve import PrivateKey +from coincurve.utils import GROUP_ORDER_INT, int_to_bytes + + +def bytes_from_mnemonic(mnemonic: str) -> bytes: + seed = Bip39SeedGenerator(mnemonic).Generate() + return ( + Bip44.FromSeed(seed, Bip44Coins.COSMOS) + .DeriveDefaultPath() + .PrivateKey() + .Raw() + .ToBytes() + ) + + +@dataclass +class KeyPair: + """ + Wrapper class around `coincurve.PrivateKey` to mimic `ecdsa.SigningKey` behavior. + """ + + key: PrivateKey + + @staticmethod + def from_mnemonic(mnemonic: str) -> "KeyPair": + """ + Creates a private key from a mnemonic. + """ + return KeyPair(PrivateKey(bytes_from_mnemonic(mnemonic))) + + @staticmethod + def from_hex(hex_key: str) -> "KeyPair": + """ + Creates a private key from a hex string. + """ + return KeyPair(PrivateKey.from_hex(hex_key)) + + def sign(self, message: bytes) -> bytes: + """ + Signs a message using the private key. Signature is encoded the same way as `ecdsa.util.sigencode_string_canonize`, to cointains 64-bytes. + """ + signature = self.key.sign_recoverable(message) + return coinsign_canonize(signature) + + @property + def public_key_bytes(self) -> bytes: + """ + Returns the public key bytes of the key pair in compressed format. + """ + return self.key.public_key.format(compressed=True) + + +def coinsign_extract(signature: bytes) -> Tuple[int, int]: + assert len(signature) == 65 + + r = int.from_bytes(signature[:32], "big") + s = int.from_bytes(signature[32:64], "big") + + return r, s + + +def coinsign_canonize(signature: bytes) -> bytes: + r, s = coinsign_extract(signature) + + if s > GROUP_ORDER_INT // 2: + s = GROUP_ORDER_INT - s + + r_bytes = int_to_bytes(r) + s_bytes = int_to_bytes(s) + return r_bytes.rjust(32, b"\x00") + s_bytes.rjust(32, b"\x00") diff --git a/v4-client-py-v2/dydx_v4_client/node/builder.py b/v4-client-py-v2/dydx_v4_client/node/builder.py index 1b8c8070..cadc839f 100644 --- a/v4-client-py-v2/dydx_v4_client/node/builder.py +++ b/v4-client-py-v2/dydx_v4_client/node/builder.py @@ -2,7 +2,6 @@ from typing import List import google -from ecdsa.util import sigencode_string_canonize from google.protobuf.message import Message from v4_proto.cosmos.base.v1beta1.coin_pb2 import Coin from v4_proto.cosmos.tx.signing.v1beta1.signing_pb2 import SignMode @@ -34,7 +33,7 @@ def get_signer_info(public_key, sequence): ) -def get_signature(private_key, body, auth_info, account_number, chain_id): +def get_signature(key_pair, body, auth_info, account_number, chain_id): signdoc = SignDoc( body_bytes=body.SerializeToString(), auth_info_bytes=auth_info.SerializeToString(), @@ -42,9 +41,7 @@ def get_signature(private_key, body, auth_info, account_number, chain_id): chain_id=chain_id, ) - return private_key.sign( - signdoc.SerializeToString(), sigencode=sigencode_string_canonize - ) + return key_pair.sign(signdoc.SerializeToString()) DEFAULT_FEE = Fee( diff --git a/v4-client-py-v2/dydx_v4_client/wallet.py b/v4-client-py-v2/dydx_v4_client/wallet.py index fa9a8f90..cbeb26c2 100644 --- a/v4-client-py-v2/dydx_v4_client/wallet.py +++ b/v4-client-py-v2/dydx_v4_client/wallet.py @@ -1,56 +1,38 @@ import hashlib from dataclasses import dataclass -from functools import partial from typing import TYPE_CHECKING import bech32 -import ecdsa from Crypto.Hash import RIPEMD160 -from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins + from v4_proto.cosmos.crypto.secp256k1.keys_pb2 import PubKey +from dydx_v4_client.key_pair import KeyPair + if TYPE_CHECKING: from dydx_v4_client.node.client import NodeClient -from_string = partial( - ecdsa.SigningKey.from_string, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 -) - - -def bytes_from_mnemonic(mnemonic: str) -> bytes: - seed = Bip39SeedGenerator(mnemonic).Generate() - return ( - Bip44.FromSeed(seed, Bip44Coins.COSMOS) - .DeriveDefaultPath() - .PrivateKey() - .Raw() - .ToBytes() - ) - - -def from_mnemonic(mnemonic: str) -> ecdsa.SigningKey: - return from_string(bytes_from_mnemonic(mnemonic)) - - @dataclass class Wallet: - key: ecdsa.SigningKey + key: KeyPair account_number: int sequence: int @staticmethod async def from_mnemonic(node: "NodeClient", mnemonic: str, address: str): account = await node.get_account(address) - return Wallet(from_mnemonic(mnemonic), account.account_number, account.sequence) + return Wallet( + KeyPair.from_mnemonic(mnemonic), account.account_number, account.sequence + ) @property def public_key(self) -> PubKey: - return PubKey(key=self.key.get_verifying_key().to_string("compressed")) + return PubKey(key=self.key.public_key_bytes) @property def address(self) -> str: - public_key_bytes = self.public_key.key + public_key_bytes = self.key.public_key_bytes sha256_hash = hashlib.sha256(public_key_bytes).digest() ripemd160_hash = RIPEMD160.new(sha256_hash).digest() return bech32.bech32_encode("dydx", bech32.convertbits(ripemd160_hash, 8, 5)) diff --git a/v4-client-py-v2/examples/basic_adder.py b/v4-client-py-v2/examples/basic_adder.py index e8712a53..9b30b348 100644 --- a/v4-client-py-v2/examples/basic_adder.py +++ b/v4-client-py-v2/examples/basic_adder.py @@ -13,7 +13,8 @@ from dydx_v4_client.network import TESTNET from dydx_v4_client.node.client import NodeClient from dydx_v4_client.node.message import order, order_id -from dydx_v4_client.wallet import Wallet, from_string +from dydx_v4_client.key_pair import KeyPair +from dydx_v4_client.wallet import Wallet from tests.conftest import DYDX_TEST_PRIVATE_KEY logging.basicConfig( @@ -37,7 +38,7 @@ def __init__( self, node_client: NodeClient, address: str, key: str, subaccount_number: int ): self.address = address - self.key = from_string(bytes.fromhex(key)) + self.key = KeyPair.from_hex(key) self.subaccount_number = subaccount_number self.node_client = node_client self.testnet_indexer_socket = IndexerSocket( diff --git a/v4-client-py-v2/poetry.lock b/v4-client-py-v2/poetry.lock index d2655998..16c4681f 100644 --- a/v4-client-py-v2/poetry.lock +++ b/v4-client-py-v2/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. [[package]] name = "anyio" @@ -6,6 +6,8 @@ version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, @@ -28,6 +30,8 @@ version = "1.5.1" description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, @@ -39,6 +43,8 @@ version = "1.2.0" description = "Backport of CPython tarfile module" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\"" files = [ {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, @@ -54,6 +60,8 @@ version = "1.2.0" description = "Reference implementation for Bech32 and segwit addresses." optional = false python-versions = ">=3.5" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"}, {file = "bech32-1.2.0.tar.gz", hash = "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899"}, @@ -65,6 +73,8 @@ version = "2.9.3" description = "Generation of mnemonics, seeds, private/public keys and addresses for different types of cryptocurrencies" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "bip_utils-2.9.3-py3-none-any.whl", hash = "sha256:ee26b8417a576c7f89b847da37316db01a5cece1994c1609d37fbeefb91ad45e"}, {file = "bip_utils-2.9.3.tar.gz", hash = "sha256:72a8c95484b57e92311b0b2a3d5195b0ce4395c19a0b157d4a289e8b1300f48a"}, @@ -101,6 +111,8 @@ version = "24.4.2" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, @@ -147,6 +159,8 @@ version = "5.6.4" description = "CBOR (de)serializer with extensive tag support" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "cbor2-5.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c40c68779a363f47a11ded7b189ba16767391d5eae27fac289e7f62b730ae1fc"}, {file = "cbor2-5.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0625c8d3c487e509458459de99bf052f62eb5d773cc9fc141c6a6ea9367726d"}, @@ -198,6 +212,8 @@ version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, @@ -209,6 +225,7 @@ version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, @@ -263,6 +280,7 @@ files = [ {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] +markers = {main = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"", dev = "platform_python_implementation != \"PyPy\" and sys_platform == \"linux\" and (python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\")"} [package.dependencies] pycparser = "*" @@ -273,6 +291,8 @@ version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -284,6 +304,8 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -383,6 +405,8 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -397,6 +421,8 @@ version = "20.0.0" description = "Cross-platform Python CFFI bindings for libsecp256k1" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "coincurve-20.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d559b22828638390118cae9372a1bb6f6594f5584c311deb1de6a83163a0919b"}, {file = "coincurve-20.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d7f6ebd90fcc550f819f7f2cce2af525c342aac07f0ccda46ad8956ad9d99b"}, @@ -463,6 +489,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "(sys_platform == \"win32\" or platform_system == \"Windows\") and (python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\")" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -474,6 +502,8 @@ version = "1.7" description = "CRC Generator" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, ] @@ -484,6 +514,8 @@ version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "(python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\") and sys_platform == \"linux\"" files = [ {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, @@ -538,6 +570,8 @@ version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, @@ -549,6 +583,8 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -560,6 +596,8 @@ version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, @@ -578,6 +616,8 @@ version = "1.4.1" description = "Ed25519 public-key signatures (BLAKE2b fork)" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "ed25519-blake2b-1.4.1.tar.gz", hash = "sha256:731e9f93cd1ac1a64649575f3519a99ffe0bb1e4cf7bf5f5f0be513a39df7363"}, ] @@ -588,6 +628,8 @@ version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version <= \"3.10\"" files = [ {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, @@ -602,6 +644,8 @@ version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, @@ -618,6 +662,8 @@ version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, @@ -676,6 +722,8 @@ version = "1.64.1" description = "Protobuf code generator for gRPC" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "grpcio_tools-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:6c8181318e3a21827c2f834fd0505040aa8f24fb568a154ff1c95c9802c0e3f5"}, {file = "grpcio_tools-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:24340327f7fb85f7406910c9484f98dd9588bdf639578b9341920d67f64306a0"}, @@ -736,6 +784,8 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -747,6 +797,8 @@ version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, @@ -768,6 +820,8 @@ version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, @@ -792,6 +846,8 @@ version = "2.5.36" description = "File identification library for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, @@ -806,6 +862,8 @@ version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main", "dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -817,6 +875,8 @@ version = "7.2.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "importlib_metadata-7.2.1-py3-none-any.whl", hash = "sha256:ffef94b0b66046dd8ea2d619b701fe978d9264d38f3998bc4c27ec3b146a87c8"}, {file = "importlib_metadata-7.2.1.tar.gz", hash = "sha256:509ecb2ab77071db5137c655e24ceb3eee66e7bbc6574165d0d114d9fc4bbe68"}, @@ -836,6 +896,8 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -847,6 +909,8 @@ version = "3.4.0" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, @@ -865,6 +929,8 @@ version = "5.3.0" description = "Useful decorators and context managers" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jaraco.context-5.3.0-py3-none-any.whl", hash = "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266"}, {file = "jaraco.context-5.3.0.tar.gz", hash = "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2"}, @@ -883,6 +949,8 @@ version = "4.0.1" description = "Functools like those found in stdlib" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jaraco.functools-4.0.1-py3-none-any.whl", hash = "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664"}, {file = "jaraco_functools-4.0.1.tar.gz", hash = "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8"}, @@ -901,6 +969,8 @@ version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "(python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\") and sys_platform == \"linux\"" files = [ {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, @@ -916,6 +986,8 @@ version = "25.2.1" description = "Store and access your passwords safely." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "keyring-25.2.1-py3-none-any.whl", hash = "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50"}, {file = "keyring-25.2.1.tar.gz", hash = "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b"}, @@ -941,6 +1013,8 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -965,6 +1039,8 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -976,6 +1052,8 @@ version = "10.3.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, @@ -987,6 +1065,8 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -998,6 +1078,8 @@ version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" +groups = ["examples"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1009,6 +1091,8 @@ version = "0.2.17" description = "Python bindings to the ammonia HTML sanitization library." optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "nh3-0.2.17-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9"}, {file = "nh3-0.2.17-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a"}, @@ -1034,6 +1118,8 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1045,6 +1131,8 @@ version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -1056,6 +1144,8 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1067,6 +1157,8 @@ version = "1.11.1" description = "Query metadata from sdists / bdists / installed packages." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pkginfo-1.11.1-py3-none-any.whl", hash = "sha256:bfa76a714fdfc18a045fcd684dbfc3816b603d9d075febef17cb6582bea29573"}, {file = "pkginfo-1.11.1.tar.gz", hash = "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa"}, @@ -1081,6 +1173,8 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -1097,6 +1191,8 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1112,6 +1208,8 @@ version = "3.7.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, @@ -1130,6 +1228,8 @@ version = "5.27.1" description = "" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "protobuf-5.27.1-cp310-abi3-win32.whl", hash = "sha256:3adc15ec0ff35c5b2d0992f9345b04a540c1e73bfee3ff1643db43cc1d734333"}, {file = "protobuf-5.27.1-cp310-abi3-win_amd64.whl", hash = "sha256:25236b69ab4ce1bec413fd4b68a15ef8141794427e0b4dc173e9d5d9dffc3bcd"}, @@ -1150,6 +1250,8 @@ version = "0.2.0" description = "Python bindings for sr25519 library" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "py_sr25519_bindings-0.2.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:86cc1a571852a4f2ade827ebf211e066b23ab805d3e864cbe213a3d8cd53f7d5"}, {file = "py_sr25519_bindings-0.2.0-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:453c9088e39dd04b07bf3ada6c473a5349c4dfd965009a35124b2c807117eda8"}, @@ -1231,10 +1333,12 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +markers = {main = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"", dev = "platform_python_implementation != \"PyPy\" and sys_platform == \"linux\" and (python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\")"} [[package]] name = "pycryptodome" @@ -1242,6 +1346,8 @@ version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, @@ -1283,6 +1389,8 @@ version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -1297,6 +1405,8 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -1323,6 +1433,8 @@ version = "8.2.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, @@ -1345,6 +1457,8 @@ version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, @@ -1363,6 +1477,8 @@ version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -1377,6 +1493,8 @@ version = "0.2.2" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "(python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\") and sys_platform == \"win32\"" files = [ {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, @@ -1388,6 +1506,8 @@ version = "6.0.1" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, @@ -1407,6 +1527,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1447,6 +1568,8 @@ version = "43.0" description = "readme_renderer is a library for rendering readme descriptions for Warehouse" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "readme_renderer-43.0-py3-none-any.whl", hash = "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9"}, {file = "readme_renderer-43.0.tar.gz", hash = "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311"}, @@ -1466,6 +1589,8 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1487,6 +1612,8 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -1501,6 +1628,8 @@ version = "2.0.0" description = "Validating URI References per RFC 3986" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, @@ -1515,6 +1644,8 @@ version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, @@ -1533,6 +1664,8 @@ version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "(python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\") and sys_platform == \"linux\"" files = [ {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, @@ -1548,6 +1681,8 @@ version = "70.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, @@ -1563,6 +1698,8 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -1574,6 +1711,8 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -1585,6 +1724,8 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -1596,6 +1737,8 @@ version = "4.0.2" description = "Collection of utilities for publishing packages on PyPI" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "twine-4.0.2-py3-none-any.whl", hash = "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8"}, {file = "twine-4.0.2.tar.gz", hash = "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"}, @@ -1618,6 +1761,8 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -1629,6 +1774,8 @@ version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, @@ -1646,6 +1793,8 @@ version = "5.2.1" description = "Protos for dYdX Chain protocol" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "v4-proto-5.2.1.tar.gz", hash = "sha256:7de9f84cc13adcdae7ab920b0c615d8a878bb4006e11ef501188685fc9b5a9ec"}, {file = "v4_proto-5.2.1-py3-none-any.whl", hash = "sha256:8b4c802c14fb5d2662191e329129218c26547d296e4f5e745e8217338355b66c"}, @@ -1662,6 +1811,8 @@ version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, @@ -1682,6 +1833,8 @@ version = "1.8.0" description = "WebSocket client for Python with low level API options" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, @@ -1698,6 +1851,8 @@ version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version <= \"3.10\" or python_version == \"3.11\" or python_version >= \"3.12\"" files = [ {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, @@ -1708,6 +1863,6 @@ doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linke test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.9" -content-hash = "8554d8aff1f50abaeb0ef9f86af09f79ab7835f9f93434cbbae4da906408b253" +content-hash = "c7933c7962e14820093ce59c37c05e1c0f80c13bd3d1869227f7d49f4715c863" diff --git a/v4-client-py-v2/pyproject.toml b/v4-client-py-v2/pyproject.toml index ff6db3d0..f1c94dea 100644 --- a/v4-client-py-v2/pyproject.toml +++ b/v4-client-py-v2/pyproject.toml @@ -14,11 +14,11 @@ v4-proto = "5.2.1" httpx = "^0.27.0" websocket-client = "^1.7.0" bip-utils = "^2.9.3" -ecdsa = "^0.19.0" typing-extensions = "^4.12.2" bech32 = "^1.2.0" pycryptodome = "^3.20.0" grpcio = "1.65.4" +coincurve = "^20.0.0" [tool.poetry.group.dev.dependencies] @@ -37,4 +37,4 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.isort] -profile = "black" \ No newline at end of file +profile = "black" diff --git a/v4-client-py-v2/tests/conftest.py b/v4-client-py-v2/tests/conftest.py index 1a597d66..86573754 100644 --- a/v4-client-py-v2/tests/conftest.py +++ b/v4-client-py-v2/tests/conftest.py @@ -13,7 +13,8 @@ from dydx_v4_client.network import TESTNET, TESTNET_FAUCET, TESTNET_NOBLE from dydx_v4_client.node.client import NodeClient from dydx_v4_client.node.message import order, order_id -from dydx_v4_client.wallet import Wallet, from_mnemonic +from dydx_v4_client.wallet import Wallet +from dydx_v4_client.key_pair import KeyPair pytest_plugins = ("pytest_asyncio",) @@ -24,6 +25,9 @@ "mirror actor skill push coach wait confirm orchard lunch mobile athlete gossip awake " "miracle matter bus reopen team ladder lazy list timber render wait" ) +DYDX_TEST_PUBLIC_KEY = ( + "03f0be763f781b5b59ebc37d721beda913148a539425baa720b97d4820f652ed75" +) TEST_ADDRESS = "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art" RECIPIENT = "dydx1slanxj8x9ntk9knwa6cvfv2tzlsq5gk3dshml0" @@ -60,14 +64,19 @@ def test_address(): return TEST_ADDRESS +@pytest.fixture +def test_public_key(): + return DYDX_TEST_PUBLIC_KEY + + @pytest.fixture def recipient(): return RECIPIENT @pytest.fixture -def private_key(): - return from_mnemonic(DYDX_TEST_MNEMONIC) +def key_pair(): + return KeyPair.from_mnemonic(DYDX_TEST_MNEMONIC) @pytest.fixture @@ -94,14 +103,14 @@ def test_order(test_order_id): ) -async def get_wallet(node_client, private_key, test_address): +async def get_wallet(node_client, key_pair, test_address): account = await node_client.get_account(test_address) - return Wallet(private_key, account.account_number, account.sequence) + return Wallet(key_pair, account.account_number, account.sequence) @pytest.fixture() -async def wallet(node_client, private_key, test_address): - return await get_wallet(node_client, private_key, test_address) +async def wallet(node_client, key_pair, test_address): + return await get_wallet(node_client, key_pair, test_address) def retry_on_forbidden(max_retries=3, delay=1, skip=False): diff --git a/v4-client-py-v2/tests/test_crypto.py b/v4-client-py-v2/tests/test_crypto.py new file mode 100644 index 00000000..1b92c2df --- /dev/null +++ b/v4-client-py-v2/tests/test_crypto.py @@ -0,0 +1,57 @@ +import hashlib +from typing import Tuple + + +from dydx_v4_client.key_pair import KeyPair +from dydx_v4_client.wallet import ( + Wallet, +) + +from tests.conftest import ( + DYDX_TEST_MNEMONIC as test_mnemonic, + DYDX_TEST_PRIVATE_KEY as test_private_key, +) + + +def test_address_derivation(test_address): + wallet = Wallet(KeyPair.from_mnemonic(test_mnemonic), 0, 0) + assert wallet.address == test_address + + +def test_address_derivation2(test_address): + wallet = Wallet(KeyPair.from_hex(test_private_key), 0, 0) + assert wallet.address == test_address + + +def test_assert_public_key_compressed_format(test_public_key): + key = KeyPair.from_hex(test_private_key) + assert key.public_key_bytes.hex() == test_public_key + + +def test_assert_public_key(test_public_key): + wallet = Wallet(KeyPair.from_hex(test_private_key), 0, 0) + assert wallet.public_key.key.hex() == test_public_key + + +def test_assert_public_key2(test_public_key): + wallet = Wallet(KeyPair.from_hex(test_private_key), 0, 0) + assert wallet.public_key.key.hex() == test_public_key + + +def test_key_serialization(): + key = KeyPair.from_hex(test_private_key) + assert key.key.to_hex() == test_private_key + + +def test_message_signing(): + key = KeyPair.from_hex(test_private_key) + message = b"hello, world!" + + signature = key.sign(message) + assert len(signature) == 64 + + # signature verification + # NOTE: Because our signature is encoded in 64-bytes canonical format, + # we need to use `ecdsa` library to verify it. + # Production code does not need signature verification so we could. + # entirerly remove ecdsa dependency. diff --git a/v4-client-py-v2/tests/test_mutating_node_client.py b/v4-client-py-v2/tests/test_mutating_node_client.py index 7c4ace5c..b950d227 100644 --- a/v4-client-py-v2/tests/test_mutating_node_client.py +++ b/v4-client-py-v2/tests/test_mutating_node_client.py @@ -74,7 +74,7 @@ async def test_send_token(node_client, wallet, test_address, recipient): @pytest.mark.asyncio async def test_order( - node_client, test_order, test_order_id, test_address, private_key, wallet + node_client, test_order, test_order_id, test_address, key_pair, wallet ): try: placed = await node_client.place_order( @@ -89,7 +89,7 @@ async def test_order( # codespace: "clob"\n code:...hj67cghhf9jypslcf9sh2n5k6art Number:0} ClientId:13850897 OrderFlags:64 ClobPairId:0}: Stateful order does not exist" time.sleep(1.5) - wallet = await get_wallet(node_client, private_key, test_address) + wallet = await get_wallet(node_client, key_pair, test_address) canceled = await node_client.cancel_order( wallet, From 0437f7b583f4494e9c6fa23dc5a75b68f361c7c6 Mon Sep 17 00:00:00 2001 From: ttl33 <19664986+ttl33@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:42:43 -0500 Subject: [PATCH 7/8] chore: bump `v4-client-py-v2` version to `1.1.4` (#316) Includes - https://github.com/dydxprotocol/v4-clients/pull/312 --- v4-client-py-v2/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v4-client-py-v2/pyproject.toml b/v4-client-py-v2/pyproject.toml index f1c94dea..c89c974c 100644 --- a/v4-client-py-v2/pyproject.toml +++ b/v4-client-py-v2/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dydx-v4-client" -version = "1.1.3" +version = "1.1.4" description = "" authors = [ "Saul Martin ", From 2af188f4c5731c12c271ff79af5a8a3b8883557b Mon Sep 17 00:00:00 2001 From: Denis Kolodin Date: Tue, 28 Jan 2025 11:17:14 +0100 Subject: [PATCH 8/8] feat(config): Implement Serialize trait for configuration structs (#314) This commit adds support for serializing configuration structures by implementing the `Serialize` trait for them. This change is necessary for enabling configuration data to be converted into formats like JSON or TOML, which facilitates easier storage, transmission, or debugging. By leveraging the `Serialize` trait, developers can integrate the configuration with existing systems that require serialized data formats. --- v4-client-rs/client/src/config.rs | 4 ++-- v4-client-rs/client/src/faucet.rs | 2 +- v4-client-rs/client/src/indexer/config.rs | 4 ++-- v4-client-rs/client/src/indexer/rest/config.rs | 4 ++-- v4-client-rs/client/src/indexer/sock/config.rs | 4 ++-- v4-client-rs/client/src/noble/config.rs | 4 ++-- v4-client-rs/client/src/node/config.rs | 4 ++-- v4-client-rs/client/src/node/types.rs | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/v4-client-rs/client/src/config.rs b/v4-client-rs/client/src/config.rs index 5ed33acf..6283a8e2 100644 --- a/v4-client-rs/client/src/config.rs +++ b/v4-client-rs/client/src/config.rs @@ -4,12 +4,12 @@ use super::faucet::FaucetConfig; use super::noble::NobleConfig; use super::{indexer::IndexerConfig, node::NodeConfig}; use anyhow::Error; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::path::Path; use tokio::fs; /// Serves as a configuration wrapper over configurations for specific clients. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct ClientConfig { /// Configuration for [`IndexerClient`](crate::indexer::IndexerClient) pub indexer: IndexerConfig, diff --git a/v4-client-rs/client/src/faucet.rs b/v4-client-rs/client/src/faucet.rs index d75032f1..58eec6a6 100644 --- a/v4-client-rs/client/src/faucet.rs +++ b/v4-client-rs/client/src/faucet.rs @@ -5,7 +5,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; /// Configuration for the Faucet client. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct FaucetConfig { /// The base url of the faucet service. pub endpoint: String, diff --git a/v4-client-rs/client/src/indexer/config.rs b/v4-client-rs/client/src/indexer/config.rs index 64248ac6..c08c2d48 100644 --- a/v4-client-rs/client/src/indexer/config.rs +++ b/v4-client-rs/client/src/indexer/config.rs @@ -1,8 +1,8 @@ pub use crate::indexer::{rest::RestConfig, sock::SockConfig}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// Indexer client configuration. -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct IndexerConfig { /// Indexer REST client configuration. #[serde(alias = "http")] diff --git a/v4-client-rs/client/src/indexer/rest/config.rs b/v4-client-rs/client/src/indexer/rest/config.rs index 7d7d7e88..477789a1 100644 --- a/v4-client-rs/client/src/indexer/rest/config.rs +++ b/v4-client-rs/client/src/indexer/rest/config.rs @@ -1,7 +1,7 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// REST Indexer client configuration. -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct RestConfig { /// REST endpoint. /// diff --git a/v4-client-rs/client/src/indexer/sock/config.rs b/v4-client-rs/client/src/indexer/sock/config.rs index d1afa635..d1762722 100644 --- a/v4-client-rs/client/src/indexer/sock/config.rs +++ b/v4-client-rs/client/src/indexer/sock/config.rs @@ -1,8 +1,8 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::num::NonZeroU32; /// Websocket Indexer client configuration. -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct SockConfig { /// Websocket endpoint. /// diff --git a/v4-client-rs/client/src/noble/config.rs b/v4-client-rs/client/src/noble/config.rs index 16053481..b7c9e562 100644 --- a/v4-client-rs/client/src/noble/config.rs +++ b/v4-client-rs/client/src/noble/config.rs @@ -1,9 +1,9 @@ use crate::indexer::Denom; use cosmrs::tendermint::chain::Id as ChainId; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// Configuration for [`NobleClient`](crate::noble::NobleClient) -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct NobleConfig { /// Node endpoint. pub endpoint: String, diff --git a/v4-client-rs/client/src/node/config.rs b/v4-client-rs/client/src/node/config.rs index 4461adad..7b50882c 100644 --- a/v4-client-rs/client/src/node/config.rs +++ b/v4-client-rs/client/src/node/config.rs @@ -1,9 +1,9 @@ use crate::indexer::Denom; use crate::node::ChainId; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// Configuration for [`NodeClient`](crate::node::NodeClient) -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct NodeConfig { /// Node endpoint. /// diff --git a/v4-client-rs/client/src/node/types.rs b/v4-client-rs/client/src/node/types.rs index 8267081b..ec48ca98 100644 --- a/v4-client-rs/client/src/node/types.rs +++ b/v4-client-rs/client/src/node/types.rs @@ -1,12 +1,12 @@ use cosmrs::tendermint::{chain::Id, error::Error}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use strum::{AsRefStr, Display}; /// [Chain ID](https://docs.dydx.exchange/infrastructure_providers-network/network_constants#chain-id) /// serves as a unique chain identificator to prevent replay attacks. /// /// See also [Cosmos ecosystem](https://cosmos.directory/). -#[derive(Debug, Eq, PartialEq, Clone, Display, AsRefStr, Deserialize)] +#[derive(Debug, Eq, PartialEq, Clone, Display, AsRefStr, Deserialize, Serialize)] pub enum ChainId { /// Testnet. #[strum(serialize = "dydx-testnet-4")]