@dydxprotocol/v4-client-js 1.6.1 → 1.8.0

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.
@@ -15,6 +15,9 @@ import {
15
15
  withdraw,
16
16
  withdrawToIBC,
17
17
  wrappedError,
18
+ getMegavaultOwnerShares,
19
+ depositToMegavault,
20
+ withdrawFromMegavault,
18
21
  } from '../src/clients/native';
19
22
  import { DYDX_TEST_ADDRESS, DYDX_TEST_MNEMONIC } from './constants';
20
23
 
@@ -47,6 +50,19 @@ async function test(): Promise<void> {
47
50
  const userStats = await getUserStats(payload);
48
51
  console.log(userStats);
49
52
 
53
+ const balances1 = await getAccountBalances();
54
+ console.log(balances1);
55
+
56
+ const vaultOwnerShares = await getMegavaultOwnerShares(payload);
57
+ console.log(vaultOwnerShares);
58
+
59
+ const depositResult = await depositToMegavault(0, 2);
60
+ console.log(depositResult);
61
+
62
+ const withdrawResult = await withdrawFromMegavault(0, 1, 0);
63
+ console.log(withdrawResult);
64
+
65
+
50
66
  const sendTokenPayload = {
51
67
  subaccountNumber: 0,
52
68
  amount: '10', // Dydx Token
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dydxprotocol/v4-client-js",
3
- "version": "1.6.1",
3
+ "version": "1.8.0",
4
4
  "description": "General client library for the new dYdX system (v4 decentralized)",
5
5
  "main": "build/src/index.js",
6
6
  "scripts": {
@@ -23,6 +23,7 @@ export const MAINNET_CHAIN_ID = 'dydx-mainnet-1';
23
23
  // ------------ API URLs ------------
24
24
  export enum IndexerApiHost {
25
25
  TESTNET = 'https://indexer.v4testnet.dydx.exchange/',
26
+ STAGING = 'https://indexer.v4staging.dydx.exchange/',
26
27
  LOCAL = 'http://localhost:3002',
27
28
  // For the deployment by DYDX token holders
28
29
  MAINNET = 'https://indexer.dydx.trade',
@@ -30,6 +31,7 @@ export enum IndexerApiHost {
30
31
 
31
32
  export enum IndexerWSHost {
32
33
  TESTNET = 'wss://dydx-testnet.imperator.co/v4/ws',
34
+ STAGING = 'wss://indexer.v4staging.dydx.exchange/v4/ws',
33
35
  LOCAL = 'ws://localhost:3003',
34
36
  // For the deployment by DYDX token holders
35
37
  MAINNET = 'wss://indexer.dydx.trade/v4/ws',
@@ -41,6 +43,7 @@ export enum FaucetApiHost {
41
43
 
42
44
  export enum ValidatorApiHost {
43
45
  TESTNET = 'https://test-dydx.kingnodes.com',
46
+ STAGING = 'https://validator.v4staging.dydx.exchange',
44
47
  LOCAL = 'http://localhost:26657',
45
48
  // For the deployment by DYDX token holders
46
49
  MAINNET = 'https://dydx-ops-rpc.kingnodes.com:443',
@@ -220,6 +223,7 @@ export class ValidatorConfig {
220
223
  public denoms: DenomConfig;
221
224
  public broadcastOptions?: BroadcastOptions;
222
225
  public defaultClientMemo?: string;
226
+ public useTimestampNonce?: boolean;
223
227
 
224
228
  constructor(
225
229
  restEndpoint: string,
@@ -227,6 +231,7 @@ export class ValidatorConfig {
227
231
  denoms: DenomConfig,
228
232
  broadcastOptions?: BroadcastOptions,
229
233
  defaultClientMemo?: string,
234
+ useTimestampNonce?: boolean,
230
235
  ) {
231
236
  this.restEndpoint = restEndpoint?.endsWith('/') ? restEndpoint.slice(0, -1) : restEndpoint;
232
237
  this.chainId = chainId;
@@ -234,6 +239,7 @@ export class ValidatorConfig {
234
239
  this.denoms = denoms;
235
240
  this.broadcastOptions = broadcastOptions;
236
241
  this.defaultClientMemo = defaultClientMemo;
242
+ this.useTimestampNonce = useTimestampNonce;
237
243
  }
238
244
  }
239
245
 
@@ -262,6 +268,24 @@ export class Network {
262
268
  return new Network('testnet', indexerConfig, validatorConfig);
263
269
  }
264
270
 
271
+ static staging(): Network {
272
+ const indexerConfig = new IndexerConfig(IndexerApiHost.STAGING, IndexerWSHost.STAGING);
273
+ const validatorConfig = new ValidatorConfig(
274
+ ValidatorApiHost.STAGING,
275
+ TESTNET_CHAIN_ID,
276
+ {
277
+ CHAINTOKEN_DENOM: 'adv4tnt',
278
+ USDC_DENOM: 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5',
279
+ USDC_GAS_DENOM: 'uusdc',
280
+ USDC_DECIMALS: 6,
281
+ CHAINTOKEN_DECIMALS: 18,
282
+ },
283
+ undefined,
284
+ 'Client Example',
285
+ );
286
+ return new Network('staging', indexerConfig, validatorConfig);
287
+ }
288
+
265
289
  static local(): Network {
266
290
  const indexerConfig = new IndexerConfig(IndexerApiHost.LOCAL, IndexerWSHost.LOCAL);
267
291
  const validatorConfig = new ValidatorConfig(
@@ -55,9 +55,10 @@ export class Post {
55
55
  public readonly defaultGasPrice: GasPrice;
56
56
  public readonly defaultDydxGasPrice: GasPrice;
57
57
 
58
+ public useTimestampNonce: boolean = false;
58
59
  private accountNumberCache: Map<string, Account> = new Map();
59
60
 
60
- constructor(get: Get, chainId: string, denoms: DenomConfig, defaultClientMemo?: string) {
61
+ constructor(get: Get, chainId: string, denoms: DenomConfig, defaultClientMemo?: string, useTimestampNonce?: boolean) {
61
62
  this.get = get;
62
63
  this.chainId = chainId;
63
64
  this.registry = generateRegistry();
@@ -74,6 +75,7 @@ export class Post {
74
75
  : denoms.CHAINTOKEN_DENOM
75
76
  }`,
76
77
  );
78
+ if (useTimestampNonce === true) this.useTimestampNonce = useTimestampNonce;
77
79
  }
78
80
 
79
81
  /**
@@ -113,14 +115,23 @@ export class Post {
113
115
  memo?: string,
114
116
  account?: () => Promise<Account>,
115
117
  ): Promise<StdFee> {
116
- const msgsPromise = messaging();
117
- const accountPromise = account ? await account() : this.account(wallet.address!);
118
- const msgsAndAccount = await Promise.all([msgsPromise, accountPromise]);
119
- const msgs = msgsAndAccount[0];
118
+ let msgs: EncodeObject[];
119
+ // protocol expects timestamp nonce in UTC milliseconds, which is the unit returned by Date.now()
120
+ let sequence = Date.now();
121
+
122
+ if (this.useTimestampNonce) {
123
+ msgs = await messaging();
124
+ } else {
125
+ const msgsPromise = messaging();
126
+ const accountPromise = account ? await account() : this.account(wallet.address!);
127
+ const msgsAndAccount = await Promise.all([msgsPromise, accountPromise]);
128
+ msgs = msgsAndAccount[0];
129
+ sequence = msgsAndAccount[1].sequence;
130
+ }
120
131
 
121
132
  return this.simulateTransaction(
122
133
  wallet.pubKey!,
123
- msgsAndAccount[1].sequence,
134
+ sequence,
124
135
  msgs,
125
136
  gasPrice,
126
137
  memo,
@@ -225,16 +236,18 @@ export class Post {
225
236
  gasPrice: GasPrice = this.getGasPrice(),
226
237
  memo?: string,
227
238
  ): Promise<Uint8Array> {
239
+ // protocol expects timestamp nonce in UTC milliseconds, which is the unit returned by Date.now()
240
+ const sequence = this.useTimestampNonce ? Date.now() : account.sequence;
228
241
  // Simulate transaction if no fee is specified.
229
242
  const fee: StdFee = zeroFee
230
243
  ? {
231
244
  amount: [],
232
245
  gas: '1000000',
233
246
  }
234
- : await this.simulateTransaction(wallet.pubKey!, account.sequence, messages, gasPrice, memo);
247
+ : await this.simulateTransaction(wallet.pubKey!, sequence, messages, gasPrice, memo);
235
248
 
236
249
  const txOptions: TransactionOptions = {
237
- sequence: account.sequence,
250
+ sequence,
238
251
  accountNumber: account.accountNumber,
239
252
  chainId: this.chainId,
240
253
  };
@@ -246,11 +259,12 @@ export class Post {
246
259
  * @description Retrieve an account structure for transactions.
247
260
  * For short term orders, the sequence doesn't matter. Use cached if available.
248
261
  * For long term and conditional orders, a round trip to validator must be made.
262
+ * when timestamp nonce is supported, no need to fetch account sequence number
249
263
  */
250
264
  public async account(address: string, orderFlags?: OrderFlags): Promise<Account> {
251
- if (orderFlags === OrderFlags.SHORT_TERM) {
265
+ if (orderFlags === OrderFlags.SHORT_TERM || this.useTimestampNonce) {
252
266
  if (this.accountNumberCache.has(address)) {
253
- // For SHORT_TERM orders, the sequence doesn't matter
267
+ // If order is SHORT_TERM or if timestamp nonce is enabled, the sequence doesn't matter
254
268
  return this.accountNumberCache.get(address)!;
255
269
  }
256
270
  }
@@ -1352,3 +1352,92 @@ export async function setSelectedGasDenom(gasDenom: string): Promise<string> {
1352
1352
  return wrappedError(error);
1353
1353
  }
1354
1354
  }
1355
+
1356
+ export async function getMegavaultOwnerShares(payload: string): Promise<string> {
1357
+ try {
1358
+ const client = globalThis.client;
1359
+ if (client === undefined) {
1360
+ throw new UserError('client is not connected. Call connectClient() first');
1361
+ }
1362
+ const json = JSON.parse(payload);
1363
+ const address = json.address;
1364
+ if (address === undefined) {
1365
+ throw new UserError('address is not set');
1366
+ }
1367
+ const response =
1368
+ await globalThis.client?.validatorClient.get.getMegavaultOwnerShares(address);
1369
+ return encodeJson(response);
1370
+ } catch (e) {
1371
+ return wrappedError(e);
1372
+ }
1373
+ }
1374
+
1375
+ export async function getMegavaultWithdrawalInfo(
1376
+ sharesToWithdraw: bigint
1377
+ ): Promise<string> {
1378
+ try {
1379
+ const client = globalThis.client;
1380
+ if (client === undefined) {
1381
+ throw new UserError('client is not connected. Call connectClient() first');
1382
+ }
1383
+ const response =
1384
+ await globalThis.client?.validatorClient.get.getMegavaultWithdrawalInfo(sharesToWithdraw);
1385
+ return encodeJson(response);
1386
+ } catch (e) {
1387
+ return wrappedError(e);
1388
+ }
1389
+ }
1390
+
1391
+ export async function depositToMegavault(
1392
+ subaccountNumber: number,
1393
+ amountUsdc: number
1394
+ ): Promise<string> {
1395
+ try {
1396
+ const client = globalThis.client;
1397
+ if (client === undefined) {
1398
+ throw new UserError('client is not connected. Call connectNetwork() first');
1399
+ }
1400
+ const wallet = globalThis.wallet;
1401
+ if (wallet === undefined) {
1402
+ throw new UserError('wallet is not set. Call connectWallet() first');
1403
+ }
1404
+ const subaccount = new SubaccountInfo(wallet, subaccountNumber);
1405
+ const tx = await client.depositToMegavault(
1406
+ subaccount,
1407
+ amountUsdc,
1408
+ Method.BroadcastTxCommit,
1409
+ );
1410
+ return encodeJson(tx);
1411
+ } catch (error) {
1412
+ return wrappedError(error);
1413
+ }
1414
+ }
1415
+
1416
+ export async function withdrawFromMegavault(
1417
+ subaccountNumber: number,
1418
+ shares: number,
1419
+ minAmount: number,
1420
+ ): Promise<string> {
1421
+ try {
1422
+ const client = globalThis.client;
1423
+ if (client === undefined) {
1424
+ throw new UserError('client is not connected. Call connectNetwork() first');
1425
+ }
1426
+ const wallet = globalThis.wallet;
1427
+ if (wallet === undefined) {
1428
+ throw new UserError('wallet is not set. Call connectWallet() first');
1429
+ }
1430
+ const subaccount = new SubaccountInfo(wallet, subaccountNumber);
1431
+ const tx = await client.withdrawFromMegavault(
1432
+ subaccount,
1433
+ shares,
1434
+ minAmount,
1435
+ Method.BroadcastTxCommit,
1436
+ );
1437
+ return encodeJson(tx);
1438
+ } catch (error) {
1439
+ return wrappedError(error);
1440
+ }
1441
+ }
1442
+
1443
+
@@ -97,6 +97,7 @@ export class ValidatorClient {
97
97
  this.config.chainId,
98
98
  this.config.denoms,
99
99
  this.config.defaultClientMemo,
100
+ this.config.useTimestampNonce,
100
101
  );
101
102
  }
102
103
  }