@dydxprotocol/v4-client-js 3.0.2 → 3.0.3
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.
- package/CHANGELOG.md +2 -2
- package/build/cjs/src/index.js +3 -2
- package/build/cjs/src/lib/trading-key-utils.js +108 -0
- package/build/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/build/esm/src/index.d.ts +1 -0
- package/build/esm/src/index.d.ts.map +1 -1
- package/build/esm/src/index.js +2 -1
- package/build/esm/src/lib/trading-key-utils.d.ts +22 -0
- package/build/esm/src/lib/trading-key-utils.d.ts.map +1 -0
- package/build/esm/src/lib/trading-key-utils.js +99 -0
- package/build/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/trading-key-utils.ts +136 -0
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './types';
|
|
|
4
4
|
// Utility functions.
|
|
5
5
|
export * as helpers from './lib/helpers';
|
|
6
6
|
export * as onboarding from './lib/onboarding';
|
|
7
|
+
export * as tradingKeyUtils from './lib/trading-key-utils';
|
|
7
8
|
export * as utils from './lib/utils';
|
|
8
9
|
export * as validation from './lib/validation';
|
|
9
10
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { fromBase64, toBase64, toBech32, toHex } from '@cosmjs/encoding';
|
|
2
|
+
import { rawSecp256k1PubkeyToRawAddress } from '@cosmjs/tendermint-rpc';
|
|
3
|
+
import { generateMnemonic } from '@scure/bip39';
|
|
4
|
+
import { wordlist } from '@scure/bip39/wordlists/english';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Authenticator,
|
|
8
|
+
AuthenticatorType,
|
|
9
|
+
TYPE_URL_BATCH_CANCEL,
|
|
10
|
+
TYPE_URL_MSG_CANCEL_ORDER,
|
|
11
|
+
TYPE_URL_MSG_PLACE_ORDER,
|
|
12
|
+
} from '../clients/constants';
|
|
13
|
+
import { type Get } from '../clients/modules/get';
|
|
14
|
+
import LocalWallet from '../clients/modules/local-wallet';
|
|
15
|
+
import { BECH32_PREFIX } from './constants';
|
|
16
|
+
import { deriveHDKeyFromMnemonic } from './onboarding';
|
|
17
|
+
|
|
18
|
+
export const createNewRandomDydxWallet = async (): Promise<
|
|
19
|
+
{ privateKeyHex: string; mnemonic: string; publicKey: string; address: string } | undefined
|
|
20
|
+
> => {
|
|
21
|
+
const mnemonic = generateMnemonic(wordlist, 128);
|
|
22
|
+
const { privateKey: privateKeyRaw } = deriveHDKeyFromMnemonic(mnemonic);
|
|
23
|
+
const wallet = await LocalWallet.fromMnemonic(mnemonic, BECH32_PREFIX);
|
|
24
|
+
|
|
25
|
+
const privateKeyHex = privateKeyRaw != null ? `0x${toHex(privateKeyRaw)}` : undefined;
|
|
26
|
+
const publicKey = wallet.pubKey;
|
|
27
|
+
const address = wallet.address;
|
|
28
|
+
|
|
29
|
+
if (privateKeyHex == null || publicKey == null || address == null) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
// 12 english words
|
|
35
|
+
mnemonic,
|
|
36
|
+
// toHex of the raw private key bits
|
|
37
|
+
privateKeyHex,
|
|
38
|
+
// base64, not hex
|
|
39
|
+
publicKey: publicKey.value,
|
|
40
|
+
// valid dydx address corresponding to the key pair
|
|
41
|
+
address,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// arguments to authorize a given wallet public key to trade on behalf of the user.
|
|
46
|
+
// allows place order, cancel order, batch cancel on subaccount 0 only.
|
|
47
|
+
export const getAuthorizeNewTradingKeyArguments = ({
|
|
48
|
+
generatedWalletPubKey,
|
|
49
|
+
}: {
|
|
50
|
+
generatedWalletPubKey: string;
|
|
51
|
+
}): { type: AuthenticatorType; data: Uint8Array } => {
|
|
52
|
+
const wrapAndEncode64 = (s: string): string => toBase64(new TextEncoder().encode(s));
|
|
53
|
+
|
|
54
|
+
const messageFilterSubAuth = [
|
|
55
|
+
{
|
|
56
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
57
|
+
config: wrapAndEncode64(TYPE_URL_MSG_PLACE_ORDER),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
61
|
+
config: wrapAndEncode64(TYPE_URL_MSG_CANCEL_ORDER),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
65
|
+
config: wrapAndEncode64(TYPE_URL_BATCH_CANCEL),
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const anyOfMessageFilterConfigB64 = wrapAndEncode64(JSON.stringify(messageFilterSubAuth));
|
|
70
|
+
|
|
71
|
+
const subAuth = [
|
|
72
|
+
{
|
|
73
|
+
type: AuthenticatorType.SIGNATURE_VERIFICATION,
|
|
74
|
+
config: generatedWalletPubKey,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: AuthenticatorType.ANY_OF,
|
|
78
|
+
config: anyOfMessageFilterConfigB64,
|
|
79
|
+
},
|
|
80
|
+
// we limit to cross markets to make it slightly harder to drain user funds on low liquidity markets with trading keys
|
|
81
|
+
// could undo this in the future if people are angry about it
|
|
82
|
+
{
|
|
83
|
+
type: AuthenticatorType.SUBACCOUNT_FILTER,
|
|
84
|
+
config: wrapAndEncode64('0'),
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const jsonString = JSON.stringify(subAuth);
|
|
89
|
+
const encodedData = new TextEncoder().encode(jsonString);
|
|
90
|
+
const topLevelType = AuthenticatorType.ALL_OF;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
type: topLevelType,
|
|
94
|
+
data: encodedData,
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// redeclared to keep sub bundle size small
|
|
99
|
+
type Awaited<T> = T extends Promise<infer U> ? U : T;
|
|
100
|
+
const isTruthy = <T>(n?: T | false | null | undefined | 0): n is T => Boolean(n);
|
|
101
|
+
|
|
102
|
+
// just parses out keys that match the format created in getAuthorizeNewTradingKeyArguments
|
|
103
|
+
export const getAuthorizedTradingKeysMetadata = (
|
|
104
|
+
authorizedKeys: Awaited<ReturnType<Get['getAuthenticators']>>['accountAuthenticators'],
|
|
105
|
+
): Array<{ id: string; publicKey: string; address: string }> => {
|
|
106
|
+
return authorizedKeys
|
|
107
|
+
.map(({ config, id, type }) => {
|
|
108
|
+
if (type !== AuthenticatorType.ALL_OF) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const parsedConfig = JSON.parse(new TextDecoder().decode(config)) as
|
|
112
|
+
| Authenticator[]
|
|
113
|
+
| undefined;
|
|
114
|
+
if (parsedConfig == null) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const publicKey = parsedConfig.find(
|
|
119
|
+
(t) => t.type === AuthenticatorType.SIGNATURE_VERIFICATION,
|
|
120
|
+
)?.config;
|
|
121
|
+
if (publicKey == null || typeof publicKey !== 'string') {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const address = toBech32(
|
|
126
|
+
BECH32_PREFIX,
|
|
127
|
+
rawSecp256k1PubkeyToRawAddress(fromBase64(publicKey)),
|
|
128
|
+
);
|
|
129
|
+
return {
|
|
130
|
+
id: id.toString(),
|
|
131
|
+
publicKey,
|
|
132
|
+
address,
|
|
133
|
+
};
|
|
134
|
+
})
|
|
135
|
+
.filter(isTruthy);
|
|
136
|
+
};
|