@dydxprotocol/v4-client-js 1.15.1 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/build/examples/constants.d.ts +1 -0
  3. package/build/examples/constants.js +3 -2
  4. package/build/examples/permissioned_keys_example.d.ts +1 -0
  5. package/build/examples/permissioned_keys_example.js +85 -0
  6. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/cosmos/bundle.d.ts +158 -158
  7. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/cosmos/bundle.js +126 -126
  8. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/query.lcd.d.ts +12 -0
  9. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/query.lcd.js +34 -0
  10. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/params.d.ts +21 -0
  11. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/params.js +37 -2
  12. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/tx.d.ts +34 -1
  13. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/tx.js +72 -2
  14. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/tx.rpc.msg.d.ts +4 -1
  15. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/blocktime/tx.rpc.msg.js +7 -1
  16. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/bundle.d.ts +2021 -1711
  17. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/bundle.js +272 -266
  18. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/finalize_block.d.ts +23 -0
  19. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/finalize_block.js +64 -0
  20. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/order_removals.d.ts +5 -0
  21. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/order_removals.js +11 -1
  22. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.d.ts +31 -0
  23. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.js +94 -5
  24. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.lcd.d.ts +2 -1
  25. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.lcd.js +7 -1
  26. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.rpc.Query.d.ts +5 -1
  27. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/query.rpc.Query.js +10 -1
  28. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/streaming.d.ts +6 -1
  29. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/streaming.js +19 -2
  30. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/indexer/events/events.d.ts +79 -6
  31. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/indexer/events/events.js +78 -2
  32. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/lcd.d.ts +1 -0
  33. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/lcd.js +4 -1
  34. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/genesis.d.ts +4 -0
  35. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/genesis.js +11 -2
  36. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/query.lcd.d.ts +2 -1
  37. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/query.lcd.js +7 -1
  38. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/tx.d.ts +39 -0
  39. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/tx.js +72 -2
  40. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/tx.rpc.msg.d.ts +7 -1
  41. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/tx.rpc.msg.js +7 -1
  42. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.d.ts +25 -0
  43. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.js +64 -2
  44. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.lcd.d.ts +2 -1
  45. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.lcd.js +7 -1
  46. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.rpc.Query.d.ts +5 -1
  47. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/perpetuals/query.rpc.Query.js +10 -1
  48. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/market_param.d.ts +8 -0
  49. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/market_param.js +1 -1
  50. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/market_price.d.ts +3 -0
  51. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/market_price.js +1 -1
  52. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.d.ts +34 -0
  53. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.js +64 -2
  54. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.lcd.d.ts +2 -1
  55. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.lcd.js +7 -1
  56. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.rpc.Query.d.ts +5 -1
  57. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/query.rpc.Query.js +10 -1
  58. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/streaming.d.ts +23 -0
  59. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/prices/streaming.js +81 -0
  60. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.d.ts +25 -1
  61. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.js +63 -2
  62. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.lcd.d.ts +2 -1
  63. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.lcd.js +7 -1
  64. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.rpc.Query.d.ts +5 -1
  65. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/query.rpc.Query.js +10 -1
  66. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/revshare/tx.rpc.msg.d.ts +1 -1
  67. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/rpc.query.d.ts +4 -0
  68. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/subaccounts/streaming.d.ts +1 -1
  69. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/subaccounts/streaming.js +5 -5
  70. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/params.d.ts +21 -0
  71. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/params.js +55 -3
  72. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/query.d.ts +1 -6
  73. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/query.js +4 -12
  74. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/query.lcd.d.ts +1 -2
  75. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/query.lcd.js +1 -13
  76. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/tx.d.ts +51 -24
  77. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/dydxprotocol/vault/tx.js +98 -46
  78. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/gogoproto/bundle.js +2 -2
  79. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/google/bundle.d.ts +174 -174
  80. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/google/bundle.js +12 -12
  81. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/tendermint/bundle.d.ts +365 -365
  82. package/build/node_modules/@dydxprotocol/v4-proto/src/codegen/tendermint/bundle.js +21 -21
  83. package/build/src/clients/composite-client.d.ts +12 -3
  84. package/build/src/clients/composite-client.js +22 -8
  85. package/build/src/clients/constants.d.ts +10 -0
  86. package/build/src/clients/constants.js +17 -4
  87. package/build/src/clients/lib/registry.js +26 -22
  88. package/build/src/clients/modules/account.js +2 -2
  89. package/build/src/clients/modules/composer.d.ts +3 -0
  90. package/build/src/clients/modules/composer.js +23 -1
  91. package/build/src/clients/modules/get.d.ts +2 -0
  92. package/build/src/clients/modules/get.js +9 -1
  93. package/build/src/clients/modules/local-wallet.d.ts +4 -4
  94. package/build/src/clients/modules/local-wallet.js +3 -3
  95. package/build/src/clients/modules/post.d.ts +4 -2
  96. package/build/src/clients/modules/post.js +15 -6
  97. package/build/src/clients/modules/signer.d.ts +5 -3
  98. package/build/src/clients/modules/signer.js +53 -14
  99. package/build/src/clients/types.d.ts +1 -0
  100. package/build/src/clients/types.js +1 -1
  101. package/build/tsconfig.tsbuildinfo +1 -1
  102. package/examples/constants.ts +2 -0
  103. package/examples/permissioned_keys_example.ts +110 -0
  104. package/package.json +2 -2
  105. package/src/clients/composite-client.ts +40 -3
  106. package/src/clients/constants.ts +16 -1
  107. package/src/clients/lib/registry.ts +8 -0
  108. package/src/clients/modules/account.ts +1 -1
  109. package/src/clients/modules/composer.ts +39 -0
  110. package/src/clients/modules/get.ts +16 -0
  111. package/src/clients/modules/local-wallet.ts +6 -6
  112. package/src/clients/modules/post.ts +44 -1
  113. package/src/clients/modules/signer.ts +79 -13
  114. package/src/clients/types.ts +1 -0
@@ -15,6 +15,8 @@ export const DYDX_LOCAL_ADDRESS = 'dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4';
15
15
  export const DYDX_LOCAL_MNEMONIC =
16
16
  'merge panther lobster crazy road hollow amused security before critic about cliff exhibit cause coyote talent happy where lion river tobacco option coconut small';
17
17
 
18
+ export const DYDX_TEST_MNEMONIC_2 = 'movie yard still copper exile wear brisk chest ride dizzy novel future menu finish radar lunar claim hub middle force turtle mouse frequent embark';
19
+
18
20
  export const MARKET_BTC_USD: string = 'BTC-USD';
19
21
  export const PERPETUAL_PAIR_BTC_USD: number = 0;
20
22
 
@@ -0,0 +1,110 @@
1
+ import { TextEncoder } from 'util';
2
+
3
+ import { toBase64 } from '@cosmjs/encoding';
4
+ import { Order_TimeInForce } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/order';
5
+
6
+ import { BECH32_PREFIX } from '../src';
7
+ import { CompositeClient } from '../src/clients/composite-client';
8
+ import { AuthenticatorType, Network, OrderSide, SelectedGasDenom } from '../src/clients/constants';
9
+ import LocalWallet from '../src/clients/modules/local-wallet';
10
+ import { SubaccountInfo } from '../src/clients/subaccount';
11
+ import { DYDX_TEST_MNEMONIC, DYDX_TEST_MNEMONIC_2 } from './constants';
12
+
13
+ async function test(): Promise<void> {
14
+ const wallet1 = await LocalWallet.fromMnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX);
15
+ const wallet2 = await LocalWallet.fromMnemonic(DYDX_TEST_MNEMONIC_2, BECH32_PREFIX);
16
+
17
+ const network = Network.staging();
18
+ const client = await CompositeClient.connect(network);
19
+ client.setSelectedGasDenom(SelectedGasDenom.NATIVE);
20
+
21
+ console.log('**Client**');
22
+ console.log(client);
23
+
24
+ const subaccount1 = new SubaccountInfo(wallet1, 0);
25
+ const subaccount2 = new SubaccountInfo(wallet2, 0);
26
+
27
+ // Change second wallet pubkey
28
+ // Add an authenticator to allow wallet2 to place orders
29
+ console.log("** Adding authenticator **");
30
+ await addAuthenticator(client, subaccount1, wallet2.pubKey!.value);
31
+
32
+ const authenticators = await client.getAuthenticators(wallet1.address!);
33
+ // Last element in authenticators array is the most recently created
34
+ const lastElement = authenticators.accountAuthenticators.length - 1;
35
+ const authenticatorID = authenticators.accountAuthenticators[lastElement].id;
36
+
37
+ // Placing order using subaccount2 for subaccount1 succeeds
38
+ console.log("** Placing order with authenticator **");
39
+ await placeOrder(client, subaccount2, subaccount1, authenticatorID);
40
+
41
+ // Remove authenticator
42
+ console.log("** Removing authenticator **");
43
+ await removeAuthenticator(client, subaccount1, authenticatorID);
44
+
45
+ // Placing an order using subaccount2 will now fail
46
+ console.log("** Placing order with invalid authenticator should fail **");
47
+ await placeOrder(client, subaccount2, subaccount1, authenticatorID);
48
+ }
49
+
50
+ async function removeAuthenticator(client: CompositeClient,subaccount: SubaccountInfo, id: Long): Promise<void> {
51
+ await client.removeAuthenticator(subaccount, id);
52
+ }
53
+
54
+ async function addAuthenticator(client: CompositeClient, subaccount: SubaccountInfo, authedPubKey:string): Promise<void> {
55
+ const subAuthenticators = [{
56
+ type: AuthenticatorType.SIGNATURE_VERIFICATION,
57
+ config: authedPubKey,
58
+ },
59
+ {
60
+ type: AuthenticatorType.MESSAGE_FILTER,
61
+ config: toBase64(new TextEncoder().encode("/dydxprotocol.clob.MsgPlaceOrder")),
62
+ },
63
+ ];
64
+
65
+ const jsonString = JSON.stringify(subAuthenticators);
66
+ const encodedData = new TextEncoder().encode(jsonString);
67
+
68
+ await client.addAuthenticator(subaccount, AuthenticatorType.ALL_OF, encodedData);
69
+ }
70
+
71
+ async function placeOrder(client: CompositeClient, fromAccount: SubaccountInfo, forAccount: SubaccountInfo, authenticatorId: Long): Promise<void> {
72
+ try {
73
+ const side = OrderSide.BUY
74
+ const price = Number("1000");
75
+ const currentBlock = await client.validatorClient.get.latestBlockHeight();
76
+ const nextValidBlockHeight = currentBlock + 5;
77
+ const goodTilBlock = nextValidBlockHeight + 10;
78
+
79
+ const timeInForce = Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED;
80
+
81
+ const clientId = Math.floor(Math.random() * 10000);
82
+
83
+ const tx = await client.placeShortTermOrder(
84
+ fromAccount,
85
+ 'ETH-USD',
86
+ side,
87
+ price,
88
+ 0.01,
89
+ clientId,
90
+ goodTilBlock,
91
+ timeInForce,
92
+ false,
93
+ undefined,
94
+ {
95
+ authenticators: [authenticatorId],
96
+ accountForOrder: forAccount,
97
+ }
98
+ );
99
+ console.log('**Order Tx**');
100
+ console.log(Buffer.from(tx.hash).toString('hex'));
101
+ } catch (error) {
102
+ console.log(error.message);
103
+ }
104
+ }
105
+
106
+ test()
107
+ .then(() => {})
108
+ .catch((error) => {
109
+ console.log(error.message);
110
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dydxprotocol/v4-client-js",
3
- "version": "1.15.1",
3
+ "version": "1.16.1",
4
4
  "description": "General client library for the new dYdX system (v4 decentralized)",
5
5
  "main": "build/src/index.js",
6
6
  "scripts": {
@@ -38,8 +38,8 @@
38
38
  "@cosmjs/stargate": "^0.32.1",
39
39
  "@cosmjs/tendermint-rpc": "^0.32.1",
40
40
  "@cosmjs/utils": "^0.32.1",
41
+ "@dydxprotocol/v4-proto": "8.0.0",
41
42
  "@osmonauts/lcd": "^0.6.0",
42
- "@dydxprotocol/v4-proto": "7.0.0-dev.0",
43
43
  "@scure/bip32": "^1.1.5",
44
44
  "@scure/bip39": "^1.1.1",
45
45
  "axios": "1.1.3",
@@ -5,6 +5,7 @@ import {
5
5
  BroadcastTxAsyncResponse,
6
6
  BroadcastTxSyncResponse,
7
7
  } from '@cosmjs/tendermint-rpc/build/tendermint37';
8
+ import { GetAuthenticatorsResponse } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/query';
8
9
  import {
9
10
  Order_ConditionType,
10
11
  Order_TimeInForce,
@@ -17,6 +18,7 @@ import { bigIntToBytes } from '../lib/helpers';
17
18
  import { isStatefulOrder, verifyOrderFlags } from '../lib/validation';
18
19
  import { GovAddNewMarketParams, OrderFlags } from '../types';
19
20
  import {
21
+ AuthenticatorType,
20
22
  Network,
21
23
  OrderExecution,
22
24
  OrderSide,
@@ -66,6 +68,11 @@ export interface OrderBatchWithMarketId {
66
68
  clientIds: number[];
67
69
  }
68
70
 
71
+ export interface PermissionedKeysAccountAuth {
72
+ authenticators: Long[];
73
+ accountForOrder: SubaccountInfo;
74
+ }
75
+
69
76
  export class CompositeClient {
70
77
  public readonly network: Network;
71
78
  public gasDenom: SelectedGasDenom = SelectedGasDenom.USDC;
@@ -151,6 +158,7 @@ export class CompositeClient {
151
158
  memo?: string,
152
159
  broadcastMode?: BroadcastMode,
153
160
  account?: () => Promise<Account>,
161
+ authenticators?: Long[],
154
162
  ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
155
163
  return this.validatorClient.post.send(
156
164
  wallet,
@@ -160,6 +168,8 @@ export class CompositeClient {
160
168
  memo,
161
169
  broadcastMode,
162
170
  account,
171
+ undefined,
172
+ authenticators,
163
173
  );
164
174
  }
165
175
 
@@ -297,10 +307,15 @@ export class CompositeClient {
297
307
  timeInForce: Order_TimeInForce,
298
308
  reduceOnly: boolean,
299
309
  memo?: string,
310
+ permissionedKeysAccountAuth?: PermissionedKeysAccountAuth,
300
311
  ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
312
+ // For permissioned orders, use the permissioning account details instead of the subaccount
313
+ // This allows placing orders on behalf of another account when using permissioned keys
314
+ const accountForOrder = permissionedKeysAccountAuth ? permissionedKeysAccountAuth.accountForOrder : subaccount;
301
315
  const msgs: Promise<EncodeObject[]> = new Promise((resolve, reject) => {
316
+
302
317
  const msg = this.placeShortTermOrderMessage(
303
- subaccount,
318
+ accountForOrder,
304
319
  marketId,
305
320
  side,
306
321
  price,
@@ -311,14 +326,16 @@ export class CompositeClient {
311
326
  reduceOnly,
312
327
  );
313
328
  msg
314
- .then((it) => resolve([it]))
329
+ .then((it) => {
330
+ resolve([it]);
331
+ })
315
332
  .catch((err) => {
316
333
  console.log(err);
317
334
  reject(err);
318
335
  });
319
336
  });
320
337
  const account: Promise<Account> = this.validatorClient.post.account(
321
- subaccount.address,
338
+ accountForOrder.address,
322
339
  undefined,
323
340
  );
324
341
  return this.send(
@@ -329,6 +346,7 @@ export class CompositeClient {
329
346
  memo,
330
347
  undefined,
331
348
  () => account,
349
+ permissionedKeysAccountAuth?.authenticators,
332
350
  );
333
351
  }
334
352
 
@@ -1217,4 +1235,23 @@ export class CompositeClient {
1217
1235
  ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
1218
1236
  return this.validatorClient.post.createMarketPermissionless(ticker, subaccount, broadcastMode, gasAdjustment, memo);
1219
1237
  }
1238
+
1239
+ async addAuthenticator(
1240
+ subaccount: SubaccountInfo,
1241
+ authenticatorType: AuthenticatorType,
1242
+ data: Uint8Array,
1243
+ ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
1244
+ return this.validatorClient.post.addAuthenticator(subaccount, authenticatorType, data)
1245
+ }
1246
+
1247
+ async removeAuthenticator(
1248
+ subaccount: SubaccountInfo,
1249
+ id: Long,
1250
+ ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
1251
+ return this.validatorClient.post.removeAuthenticator(subaccount, id)
1252
+ }
1253
+
1254
+ async getAuthenticators(address: string): Promise<GetAuthenticatorsResponse>{
1255
+ return this.validatorClient.get.getAuthenticators(address);
1256
+ }
1220
1257
  }
@@ -116,6 +116,10 @@ export const TYPE_URL_MSG_UNDELEGATE = '/cosmos.staking.v1beta1.MsgUndelegate';
116
116
  export const TYPE_URL_MSG_WITHDRAW_DELEGATOR_REWARD =
117
117
  '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward';
118
118
 
119
+ // x/accountplus
120
+ export const TYPE_URL_MSG_ADD_AUTHENTICATOR = '/dydxprotocol.accountplus.MsgAddAuthenticator'
121
+ export const TYPE_URL_MSG_REMOVE_AUTHENTICATOR = '/dydxprotocol.accountplus.MsgRemoveAuthenticator'
122
+
119
123
  // ------------ Chain Constants ------------
120
124
  // The following are same across different networks / deployments.
121
125
  export const GOV_MODULE_ADDRESS = 'dydx10d07y265gmmuvt4z0w9aw880jnsr700jnmapky';
@@ -196,6 +200,17 @@ export enum PnlTickInterval {
196
200
  day = 'day',
197
201
  }
198
202
 
203
+ // ----------- Authenticators -------------
204
+
205
+ export enum AuthenticatorType {
206
+ ALL_OF = 'AllOf',
207
+ ANY_OF = 'AnyOf',
208
+ SIGNATURE_VERIFICATION = 'SignatureVerification',
209
+ MESSAGE_FILTER = 'MessageFilter',
210
+ CLOB_PAIR_ID_FILTER = 'ClobPairIdFilter',
211
+ SUBACCOUNT_FILTER = 'SubaccountFilter',
212
+ }
213
+
199
214
  export enum TradingRewardAggregationPeriod {
200
215
  DAILY = 'DAILY',
201
216
  WEEKLY = 'WEEKLY',
@@ -285,7 +300,7 @@ export class Network {
285
300
  const indexerConfig = new IndexerConfig(IndexerApiHost.STAGING, IndexerWSHost.STAGING);
286
301
  const validatorConfig = new ValidatorConfig(
287
302
  ValidatorApiHost.STAGING,
288
- TESTNET_CHAIN_ID,
303
+ STAGING_CHAIN_ID,
289
304
  {
290
305
  CHAINTOKEN_DENOM: 'adv4tnt',
291
306
  USDC_DENOM: 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5',
@@ -1,5 +1,6 @@
1
1
  import { GeneratedType, Registry } from '@cosmjs/proto-signing';
2
2
  import { defaultRegistryTypes } from '@cosmjs/stargate';
3
+ import { MsgAddAuthenticator, MsgRemoveAuthenticator } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx';
3
4
  import { MsgRegisterAffiliate } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/tx';
4
5
  import {
5
6
  MsgPlaceOrder,
@@ -38,6 +39,8 @@ import {
38
39
  TYPE_URL_MSG_WITHDRAW_FROM_MEGAVAULT,
39
40
  TYPE_URL_MSG_REGISTER_AFFILIATE,
40
41
  TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS,
42
+ TYPE_URL_MSG_ADD_AUTHENTICATOR,
43
+ TYPE_URL_MSG_REMOVE_AUTHENTICATOR,
41
44
  } from '../constants';
42
45
 
43
46
  export const registry: ReadonlyArray<[string, GeneratedType]> = [];
@@ -74,6 +77,11 @@ export function generateRegistry(): Registry {
74
77
  // affiliates
75
78
  [TYPE_URL_MSG_REGISTER_AFFILIATE, MsgRegisterAffiliate as GeneratedType],
76
79
 
80
+
81
+ // authentication
82
+ [TYPE_URL_MSG_ADD_AUTHENTICATOR, MsgAddAuthenticator as GeneratedType],
83
+ [TYPE_URL_MSG_REMOVE_AUTHENTICATOR, MsgRemoveAuthenticator as GeneratedType],
84
+
77
85
  // default types
78
86
  ...defaultRegistryTypes,
79
87
  ]);
@@ -275,7 +275,7 @@ export default class AccountClient extends RestClient {
275
275
  limit?: number | null,
276
276
  page?: number | null,
277
277
  ): Promise<Data> {
278
- const uri = '/v4//historical-pnl/parentSubaccount';
278
+ const uri = '/v4/historical-pnl/parentSubaccount';
279
279
  return this.get(uri, {
280
280
  address,
281
281
  parentSubaccountNumber,
@@ -7,6 +7,7 @@ import {
7
7
  MsgDelegate,
8
8
  MsgUndelegate,
9
9
  } from '@dydxprotocol/v4-proto/src/codegen/cosmos/staking/v1beta1/tx';
10
+ import { MsgAddAuthenticator, MsgRemoveAuthenticator } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx';
10
11
  import { MsgRegisterAffiliate } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/tx';
11
12
  import { ClobPair_Status } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/clob_pair';
12
13
  import {
@@ -52,6 +53,9 @@ import {
52
53
  TYPE_URL_MSG_DEPOSIT_TO_MEGAVAULT,
53
54
  TYPE_URL_MSG_WITHDRAW_FROM_MEGAVAULT,
54
55
  TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS,
56
+ TYPE_URL_MSG_ADD_AUTHENTICATOR,
57
+ TYPE_URL_MSG_REMOVE_AUTHENTICATOR,
58
+ AuthenticatorType,
55
59
  } from '../constants';
56
60
  import { DenomConfig } from '../types';
57
61
  import {
@@ -105,6 +109,7 @@ export class Composer {
105
109
  orderFlags,
106
110
  clobPairId,
107
111
  };
112
+
108
113
  const order: Order = {
109
114
  orderId,
110
115
  side,
@@ -575,6 +580,40 @@ export class Composer {
575
580
  }
576
581
  }
577
582
 
583
+ // ----------- x/accountplus --------
584
+
585
+ public composeMsgAddAuthenticator(
586
+ address: string,
587
+ authenticatorType: AuthenticatorType,
588
+ data: Uint8Array,
589
+ ): EncodeObject {
590
+ const msg: MsgAddAuthenticator = {
591
+ sender: address,
592
+ authenticatorType,
593
+ data,
594
+ }
595
+
596
+ return {
597
+ typeUrl: TYPE_URL_MSG_ADD_AUTHENTICATOR,
598
+ value: msg,
599
+ }
600
+ }
601
+
602
+ public composeMsgRemoveAuthenticator(
603
+ address: string,
604
+ id: Long,
605
+ ): EncodeObject {
606
+ const msg: MsgRemoveAuthenticator = {
607
+ sender: address,
608
+ id,
609
+ }
610
+
611
+ return {
612
+ typeUrl: TYPE_URL_MSG_REMOVE_AUTHENTICATOR,
613
+ value: msg,
614
+ }
615
+ }
616
+
578
617
  // ------------ util ------------
579
618
  public validateGoodTilBlockAndTime(
580
619
  orderFlags: number,
@@ -7,6 +7,7 @@ import {
7
7
  TxExtension,
8
8
  QueryAbciResponse,
9
9
  } from '@cosmjs/stargate';
10
+ import { GetAuthenticatorsRequest, GetAuthenticatorsResponse } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/query';
10
11
  import * as AuthModule from 'cosmjs-types/cosmos/auth/v1beta1/query';
11
12
  import * as BankModule from 'cosmjs-types/cosmos/bank/v1beta1/query';
12
13
  import { Any } from 'cosmjs-types/google/protobuf/any';
@@ -610,6 +611,21 @@ export class Get {
610
611
  return AffiliateModule.AffiliateWhitelistResponse.decode(data);
611
612
  }
612
613
 
614
+ async getAuthenticators(address: string): Promise<GetAuthenticatorsResponse> {
615
+ const requestData = Uint8Array.from(
616
+ GetAuthenticatorsRequest.encode({
617
+ account: address,
618
+ }).finish(),
619
+ );
620
+
621
+ const data = await this.sendQuery(
622
+ '/dydxprotocol.accountplus.Query/GetAuthenticators',
623
+ requestData,
624
+ );
625
+
626
+ return GetAuthenticatorsResponse.decode(data);
627
+ }
628
+
613
629
  private async sendQuery(requestUrl: string, requestData: Uint8Array): Promise<Uint8Array> {
614
630
  // eslint-disable-next-line max-len
615
631
  const resp: QueryAbciResponse = await this.stargateQueryClient.queryAbci(
@@ -3,7 +3,7 @@ import {
3
3
  AccountData,
4
4
  DirectSecp256k1HdWallet,
5
5
  EncodeObject,
6
- OfflineSigner,
6
+ OfflineDirectSigner,
7
7
  } from '@cosmjs/proto-signing';
8
8
  import { SigningStargateClient } from '@cosmjs/stargate';
9
9
  import Long from 'long';
@@ -22,9 +22,9 @@ export default class LocalWallet {
22
22
  address?: string;
23
23
  pubKey?: Secp256k1Pubkey;
24
24
  signer?: TransactionSigner;
25
- offlineSigner?: OfflineSigner;
25
+ offlineSigner?: OfflineDirectSigner;
26
26
 
27
- static async fromOfflineSigner(signer: OfflineSigner): Promise<LocalWallet> {
27
+ static async fromOfflineSigner(signer: OfflineDirectSigner): Promise<LocalWallet> {
28
28
  const wallet = new LocalWallet();
29
29
  await wallet.setSigner(signer);
30
30
  return wallet;
@@ -36,7 +36,7 @@ export default class LocalWallet {
36
36
  return wallet;
37
37
  }
38
38
 
39
- async setSigner(signer: OfflineSigner): Promise<void> {
39
+ async setSigner(signer: OfflineDirectSigner): Promise<void> {
40
40
  this.offlineSigner = signer;
41
41
  const stargateClient = await SigningStargateClient.offline(signer, {
42
42
  registry: generateRegistry(),
@@ -46,7 +46,7 @@ export default class LocalWallet {
46
46
  this.accounts = [...accountData];
47
47
  this.address = firstAccount.address;
48
48
  this.pubKey = encodeSecp256k1Pubkey(firstAccount.pubkey);
49
- this.signer = new TransactionSigner(this.address, stargateClient);
49
+ this.signer = new TransactionSigner(this.address, stargateClient, signer);
50
50
  }
51
51
 
52
52
  async setMnemonic(mnemonic: string, prefix?: string): Promise<void> {
@@ -60,6 +60,6 @@ export default class LocalWallet {
60
60
  fee?: StdFee,
61
61
  memo: string = '',
62
62
  ): Promise<Uint8Array> {
63
- return this.signer!.signTransaction(messages, transactionOptions, fee, memo);
63
+ return this.signer!.signTransaction(messages, transactionOptions, fee, memo, this.pubKey);
64
64
  }
65
65
  }
@@ -11,7 +11,7 @@ import _ from 'lodash';
11
11
  import Long from 'long';
12
12
  import protobuf from 'protobufjs';
13
13
 
14
- import { GAS_MULTIPLIER, SelectedGasDenom } from '../constants';
14
+ import { AuthenticatorType, GAS_MULTIPLIER, SelectedGasDenom } from '../constants';
15
15
  import { UnexpectedClientError } from '../lib/errors';
16
16
  import { generateRegistry } from '../lib/registry';
17
17
  import { SubaccountInfo } from '../subaccount';
@@ -178,6 +178,7 @@ export class Post {
178
178
  broadcastMode?: BroadcastMode,
179
179
  account?: () => Promise<Account>,
180
180
  gasAdjustment: number = GAS_MULTIPLIER,
181
+ authenticators?: Long[],
181
182
  ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
182
183
  const msgsPromise = messaging();
183
184
  const accountPromise = account ? await account() : this.account(wallet.address!);
@@ -193,6 +194,7 @@ export class Post {
193
194
  memo ?? this.defaultClientMemo,
194
195
  broadcastMode ?? this.defaultBroadcastMode(msgs),
195
196
  gasAdjustment,
197
+ authenticators,
196
198
  );
197
199
  }
198
200
 
@@ -238,6 +240,7 @@ export class Post {
238
240
  gasPrice: GasPrice = this.getGasPrice(),
239
241
  memo?: string,
240
242
  gasAdjustment: number = GAS_MULTIPLIER,
243
+ authenticators?: Long[],
241
244
  ): Promise<Uint8Array> {
242
245
  // protocol expects timestamp nonce in UTC milliseconds, which is the unit returned by Date.now()
243
246
  const sequence = this.useTimestampNonce ? Date.now() : account.sequence;
@@ -260,6 +263,7 @@ export class Post {
260
263
  sequence,
261
264
  accountNumber: account.accountNumber,
262
265
  chainId: this.chainId,
266
+ authenticators,
263
267
  };
264
268
  // Generate signed transaction.
265
269
  return wallet.signTransaction(messages, txOptions, fee, memo);
@@ -297,6 +301,7 @@ export class Post {
297
301
  memo?: string,
298
302
  broadcastMode?: BroadcastMode,
299
303
  gasAdjustment: number = GAS_MULTIPLIER,
304
+ authenticators?: Long[],
300
305
  ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
301
306
  const signedTransaction = await this.signTransaction(
302
307
  wallet,
@@ -306,6 +311,7 @@ export class Post {
306
311
  gasPrice,
307
312
  memo,
308
313
  gasAdjustment,
314
+ authenticators,
309
315
  );
310
316
  return this.sendSignedTransaction(signedTransaction, broadcastMode);
311
317
  }
@@ -944,4 +950,41 @@ export class Post {
944
950
  gasAdjustment,
945
951
  );
946
952
  }
953
+
954
+ async addAuthenticator(
955
+ subaccount: SubaccountInfo,
956
+ authenticatorType: AuthenticatorType,
957
+ data: Uint8Array,
958
+ ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
959
+ const msg = this.composer.composeMsgAddAuthenticator(subaccount.address, authenticatorType, data);
960
+
961
+ return this.send(
962
+ subaccount.wallet,
963
+ () => Promise.resolve([msg]),
964
+ false,
965
+ undefined,
966
+ undefined,
967
+ Method.BroadcastTxSync,
968
+ undefined,
969
+ undefined,
970
+ );
971
+ }
972
+
973
+ async removeAuthenticator(
974
+ subaccount: SubaccountInfo,
975
+ id: Long,
976
+ ): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
977
+ const msg = this.composer.composeMsgRemoveAuthenticator(subaccount.address, id);
978
+
979
+ return this.send(
980
+ subaccount.wallet,
981
+ () => Promise.resolve([msg]),
982
+ false,
983
+ undefined,
984
+ undefined,
985
+ Method.BroadcastTxSync,
986
+ undefined,
987
+ undefined,
988
+ );
989
+ }
947
990
  }
@@ -1,10 +1,15 @@
1
- import { EncodeObject } from '@cosmjs/proto-signing';
1
+ import { Secp256k1Pubkey } from '@cosmjs/amino';
2
+ import { fromBase64 } from '@cosmjs/encoding';
3
+ import { Int53 } from '@cosmjs/math';
4
+ import { EncodeObject, encodePubkey, makeAuthInfoBytes, makeSignDoc, OfflineDirectSigner } from '@cosmjs/proto-signing';
2
5
  import { SigningStargateClient, StdFee } from '@cosmjs/stargate';
3
- import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
6
+ import { TxExtension } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx';
7
+ import { TxBody, TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
8
+ import { Any } from 'cosmjs-types/google/protobuf/any';
4
9
  import Long from 'long';
5
10
  import protobuf from 'protobufjs';
6
11
 
7
- import { UserError } from '../lib/errors';
12
+ import { generateRegistry } from '../lib/registry';
8
13
  import { TransactionOptions } from '../types';
9
14
 
10
15
  // Required for encoding and decoding queries that are of type Long.
@@ -17,10 +22,16 @@ protobuf.configure();
17
22
  export class TransactionSigner {
18
23
  readonly address: string;
19
24
  readonly stargateSigningClient: SigningStargateClient;
25
+ readonly offlineSigner: OfflineDirectSigner;
20
26
 
21
- constructor(address: string, stargateSigningClient: SigningStargateClient) {
27
+ constructor(
28
+ address: string,
29
+ stargateSigningClient: SigningStargateClient,
30
+ offlineSigner: OfflineDirectSigner,
31
+ ) {
22
32
  this.address = address;
23
33
  this.stargateSigningClient = stargateSigningClient;
34
+ this.offlineSigner = offlineSigner;
24
35
  }
25
36
 
26
37
  /**
@@ -35,18 +46,73 @@ export class TransactionSigner {
35
46
  transactionOptions: TransactionOptions,
36
47
  fee?: StdFee,
37
48
  memo: string = '',
49
+ publicKey?: Secp256k1Pubkey,
38
50
  ): Promise<Uint8Array> {
39
- // Verify there is either a fee or a path to getting the fee present.
40
- if (fee === undefined) {
41
- throw new UserError('fee cannot be undefined');
51
+ if (!fee) {
52
+ throw new Error('Fee cannot be undefined');
42
53
  }
43
54
 
44
- // Sign, encode and return the transaction.
45
- const rawTx: TxRaw = await this.stargateSigningClient.sign(this.address, messages, fee, memo, {
46
- accountNumber: transactionOptions.accountNumber,
47
- sequence: transactionOptions.sequence,
48
- chainId: transactionOptions.chainId,
55
+ const registry = generateRegistry();
56
+
57
+ // Encode the messages
58
+ const encodedMessages = messages.map((msg) => registry.encodeAsAny(msg));
59
+
60
+ // Encode the TxExtension message
61
+ const txExtension = TxExtension.encode({
62
+ selectedAuthenticators: transactionOptions.authenticators ?? [],
63
+ }).finish();
64
+
65
+ // Create the non-critical extension message
66
+ const nonCriticalExtensionOptions: Any[] = [
67
+ Any.fromPartial({
68
+ typeUrl: '/dydxprotocol.accountplus.TxExtension',
69
+ value: txExtension,
70
+ }),
71
+ ];
72
+
73
+ // Construct the TxBody
74
+ const txBody: TxBody = TxBody.fromPartial({
75
+ messages: encodedMessages,
76
+ memo,
77
+ extensionOptions: [],
78
+ nonCriticalExtensionOptions,
49
79
  });
50
- return Uint8Array.from(TxRaw.encode(rawTx).finish());
80
+
81
+ // Encode the TxBody
82
+ const txBodyBytes = TxBody.encode(txBody).finish();
83
+
84
+ if (!publicKey) {
85
+ throw new Error('Public key cannot be undefined');
86
+ }
87
+ const pubkey = encodePubkey(publicKey); // Use the public key of the signer
88
+
89
+ const gasLimit = Int53.fromString(String(fee.gas)).toNumber();
90
+ const authInfoBytes = makeAuthInfoBytes(
91
+ [{ pubkey, sequence: transactionOptions.sequence }],
92
+ fee.amount,
93
+ gasLimit,
94
+ undefined,
95
+ undefined,
96
+ );
97
+
98
+ // Create the SignDoc
99
+ const signDoc = makeSignDoc(
100
+ txBodyBytes,
101
+ authInfoBytes,
102
+ transactionOptions.chainId,
103
+ transactionOptions.accountNumber,
104
+ );
105
+
106
+ // Use OfflineSigner to sign the transaction
107
+ const signerAddress = this.address;
108
+ const { signed, signature } = await this.offlineSigner.signDirect(signerAddress, signDoc);
109
+
110
+ const txRaw = TxRaw.fromPartial({
111
+ bodyBytes: signed.bodyBytes,
112
+ authInfoBytes: signed.authInfoBytes,
113
+ signatures: [fromBase64(signature.signature)],
114
+ });
115
+
116
+ return Uint8Array.from(TxRaw.encode(txRaw).finish());
51
117
  }
52
118
  }