@dydxprotocol/v4-client-js 3.0.2 → 3.0.4
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/LICENSE +7 -796
- package/build/cjs/examples/permissioned_keys_example.js +35 -49
- 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/examples/permissioned_keys_example.js +37 -51
- 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/examples/permissioned_keys_example.ts +66 -70
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/trading-key-utils.ts +136 -0
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Order_TimeInForce } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/order';
|
|
1
|
+
import Long from 'long';
|
|
3
2
|
import { BECH32_PREFIX } from '../src';
|
|
4
3
|
import { CompositeClient } from '../src/clients/composite-client';
|
|
5
|
-
import {
|
|
4
|
+
import { Network, OrderExecution, OrderSide, OrderTimeInForce, OrderType, SelectedGasDenom, } from '../src/clients/constants';
|
|
6
5
|
import LocalWallet from '../src/clients/modules/local-wallet';
|
|
7
6
|
import { SubaccountInfo } from '../src/clients/subaccount';
|
|
8
|
-
import {
|
|
7
|
+
import { createNewRandomDydxWallet, getAuthorizeNewTradingKeyArguments, getAuthorizedTradingKeysMetadata, } from '../src/lib/trading-key-utils';
|
|
8
|
+
import { DYDX_TEST_MNEMONIC, DYDX_TEST_MNEMONIC_2 } from './constants';
|
|
9
9
|
async function test() {
|
|
10
|
+
var _a;
|
|
10
11
|
const wallet1 = await LocalWallet.fromMnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX);
|
|
11
12
|
const wallet2 = await LocalWallet.fromMnemonic(DYDX_TEST_MNEMONIC_2, BECH32_PREFIX);
|
|
12
|
-
const
|
|
13
|
-
const network = Network.staging();
|
|
13
|
+
const network = Network.testnet();
|
|
14
14
|
const client = await CompositeClient.connect(network);
|
|
15
15
|
client.setSelectedGasDenom(SelectedGasDenom.NATIVE);
|
|
16
16
|
console.log('**Client**');
|
|
17
17
|
console.log(client);
|
|
18
18
|
const subaccount1 = SubaccountInfo.forLocalWallet(wallet1, 0);
|
|
19
19
|
const subaccount2 = SubaccountInfo.forLocalWallet(wallet2, 0);
|
|
20
|
-
const subaccount3 = SubaccountInfo.forLocalWallet(wallet3, 0);
|
|
21
20
|
// Change second wallet pubkey
|
|
22
21
|
// Add an authenticator to allow wallet2 to place orders
|
|
23
22
|
console.log('** Adding authenticator **');
|
|
@@ -25,7 +24,8 @@ async function test() {
|
|
|
25
24
|
const authsBefore = await client.getAuthenticators(wallet1.address);
|
|
26
25
|
const beforeCount = authsBefore.accountAuthenticators.length;
|
|
27
26
|
console.log(`Authenticators before: ${beforeCount}`);
|
|
28
|
-
await
|
|
27
|
+
const apiTradingWalletInfo1 = await createApiTradingWallet(client, subaccount1);
|
|
28
|
+
const apiTradingWallet1 = await LocalWallet.fromPrivateKey(apiTradingWalletInfo1.privteKeyHex, BECH32_PREFIX);
|
|
29
29
|
console.log('** Waiting 3 seconds for txn to be confirmed **');
|
|
30
30
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
31
31
|
const authsAfter = await client.getAuthenticators(wallet1.address);
|
|
@@ -38,16 +38,19 @@ async function test() {
|
|
|
38
38
|
else {
|
|
39
39
|
console.log('Authenticator count incremented by 1 as expected.');
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
41
|
+
const parsedAuths = getAuthorizedTradingKeysMetadata(authsAfter.accountAuthenticators);
|
|
42
|
+
const newAuthenticatorID = (_a = parsedAuths.find((a) => apiTradingWallet1.address != null && a.address === apiTradingWallet1.address)) === null || _a === void 0 ? void 0 : _a.id;
|
|
43
|
+
if (newAuthenticatorID == null) {
|
|
44
|
+
console.error('Unable to locate the created authenticator. Address: ', apiTradingWallet1.address);
|
|
45
|
+
throw new Error('Unable to locate the new authenticator');
|
|
46
|
+
}
|
|
44
47
|
console.log(`New authenticator ID: ${newAuthenticatorID}`);
|
|
45
48
|
// Placing order using subaccount2 for subaccount1 succeeds
|
|
46
49
|
console.log('** Placing order for subaccount1 with subaccount2 + authenticator, should succeed **');
|
|
47
|
-
await placeOrder(client,
|
|
48
|
-
// Placing order using
|
|
50
|
+
await placeOrder(client, apiTradingWallet1, subaccount1.address, newAuthenticatorID);
|
|
51
|
+
// Placing order using subaccount2 for subaccount1 should fail
|
|
49
52
|
console.log('** Placing order for subaccount1 with subaccount3 + authenticator, should fail **');
|
|
50
|
-
await placeOrder(client,
|
|
53
|
+
await placeOrder(client, subaccount2.signingWallet, subaccount1.address, newAuthenticatorID);
|
|
51
54
|
// Remove authenticator
|
|
52
55
|
console.log('** Removing authenticator **');
|
|
53
56
|
await removeAuthenticator(client, subaccount1, newAuthenticatorID);
|
|
@@ -55,51 +58,34 @@ async function test() {
|
|
|
55
58
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
56
59
|
// Placing an order using subaccount2 will now fail
|
|
57
60
|
console.log('** Placing order with removed authenticator should fail **');
|
|
58
|
-
await placeOrder(client,
|
|
61
|
+
await placeOrder(client, apiTradingWallet1, subaccount1.address, newAuthenticatorID);
|
|
59
62
|
}
|
|
60
63
|
async function removeAuthenticator(client, subaccount, id) {
|
|
61
|
-
await client.removeAuthenticator(subaccount, id
|
|
64
|
+
await client.removeAuthenticator(subaccount, id);
|
|
62
65
|
}
|
|
63
|
-
async function
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
];
|
|
75
|
-
// Nested AnyOf config must be base64(JSON([...])) as on-chain expects []byte
|
|
76
|
-
const anyOfConfigB64 = toBase64(new TextEncoder().encode(JSON.stringify(anyOfSubAuth)));
|
|
77
|
-
const subAuth = [
|
|
78
|
-
{
|
|
79
|
-
type: AuthenticatorType.SIGNATURE_VERIFICATION,
|
|
80
|
-
config: authedPubKey,
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
type: AuthenticatorType.ANY_OF,
|
|
84
|
-
config: anyOfConfigB64,
|
|
85
|
-
},
|
|
86
|
-
];
|
|
87
|
-
const jsonString = JSON.stringify(subAuth);
|
|
88
|
-
const encodedData = new TextEncoder().encode(jsonString);
|
|
89
|
-
await client.addAuthenticator(subaccount, AuthenticatorType.ALL_OF, encodedData);
|
|
66
|
+
async function createApiTradingWallet(client, subaccount) {
|
|
67
|
+
const wallet = await createNewRandomDydxWallet();
|
|
68
|
+
if (wallet == null) {
|
|
69
|
+
throw new Error("Couldn't create wallet");
|
|
70
|
+
}
|
|
71
|
+
const { data, type } = getAuthorizeNewTradingKeyArguments({
|
|
72
|
+
generatedWalletPubKey: wallet === null || wallet === void 0 ? void 0 : wallet.publicKey,
|
|
73
|
+
});
|
|
74
|
+
console.log('adding', wallet.address);
|
|
75
|
+
await client.addAuthenticator(subaccount, type, data);
|
|
76
|
+
return { privteKeyHex: wallet.privateKeyHex, forDydxAddress: subaccount.address };
|
|
90
77
|
}
|
|
91
|
-
async function placeOrder(client,
|
|
78
|
+
async function placeOrder(client, apiTradingWallet, forAccountAddress, authenticatorId) {
|
|
92
79
|
try {
|
|
93
80
|
const side = OrderSide.BUY;
|
|
94
|
-
const price = Number('
|
|
95
|
-
const currentBlock = await client.validatorClient.get.latestBlockHeight();
|
|
96
|
-
const nextValidBlockHeight = currentBlock + 5;
|
|
97
|
-
const goodTilBlock = nextValidBlockHeight + 10;
|
|
98
|
-
const timeInForce = Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED;
|
|
81
|
+
const price = Number('10000');
|
|
99
82
|
const clientId = Math.floor(Math.random() * 10000);
|
|
100
|
-
const tx = await client.
|
|
83
|
+
const tx = await client.placeOrder(SubaccountInfo.forPermissionedWallet(apiTradingWallet, forAccountAddress, 0, [
|
|
84
|
+
Long.fromString(authenticatorId),
|
|
85
|
+
]), 'ETH-USD', OrderType.MARKET, side, price, 0.01, clientId, OrderTimeInForce.IOC, 100, OrderExecution.IOC, false, false);
|
|
101
86
|
console.log('**Order Tx**');
|
|
102
87
|
console.log(Buffer.from(tx.hash).toString('hex'));
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
89
|
}
|
|
104
90
|
catch (error) {
|
|
105
91
|
console.log(error.message);
|
|
@@ -110,4 +96,4 @@ test()
|
|
|
110
96
|
.catch((error) => {
|
|
111
97
|
console.log(error.message);
|
|
112
98
|
});
|
|
113
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbmVkX2tleXNfZXhhbXBsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2V4YW1wbGVzL3Blcm1pc3Npb25lZF9rZXlzX2V4YW1wbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRXhCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDdkMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2xFLE9BQU8sRUFDTCxPQUFPLEVBQ1AsY0FBYyxFQUNkLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsU0FBUyxFQUNULGdCQUFnQixHQUNqQixNQUFNLDBCQUEwQixDQUFDO0FBQ2xDLE9BQU8sV0FBVyxNQUFNLHFDQUFxQyxDQUFDO0FBQzlELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMzRCxPQUFPLEVBQ0wseUJBQXlCLEVBQ3pCLGtDQUFrQyxFQUNsQyxnQ0FBZ0MsR0FDakMsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFdkUsS0FBSyxVQUFVLElBQUk7O0lBQ2pCLE1BQU0sT0FBTyxHQUFHLE1BQU0sV0FBVyxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsRUFBRSxhQUFhLENBQUMsQ0FBQztJQUNsRixNQUFNLE9BQU8sR0FBRyxNQUFNLFdBQVcsQ0FBQyxZQUFZLENBQUMsb0JBQW9CLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFFcEYsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2xDLE1BQU0sTUFBTSxHQUFHLE1BQU0sZUFBZSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RCxNQUFNLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFF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
|
package/build/esm/src/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './types';
|
|
2
2
|
export * as helpers from './lib/helpers';
|
|
3
3
|
export * as onboarding from './lib/onboarding';
|
|
4
|
+
export * as tradingKeyUtils from './lib/trading-key-utils';
|
|
4
5
|
export * as utils from './lib/utils';
|
|
5
6
|
export * as validation from './lib/validation';
|
|
6
7
|
export { CompositeClient } from './clients/composite-client';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AAGxB,OAAO,KAAK,OAAO,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,KAAK,MAAM,aAAa,CAAC;AACrC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AAGxB,OAAO,KAAK,OAAO,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,eAAe,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,KAAK,MAAM,aAAa,CAAC;AACrC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/build/esm/src/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from './types';
|
|
|
3
3
|
// Utility functions.
|
|
4
4
|
export * as helpers from './lib/helpers';
|
|
5
5
|
export * as onboarding from './lib/onboarding';
|
|
6
|
+
export * as tradingKeyUtils from './lib/trading-key-utils';
|
|
6
7
|
export * as utils from './lib/utils';
|
|
7
8
|
export * as validation from './lib/validation';
|
|
8
9
|
export { CompositeClient } from './clients/composite-client';
|
|
@@ -15,4 +16,4 @@ export { SubaccountInfo as SubaccountClient, SubaccountInfo } from './clients/su
|
|
|
15
16
|
export { ValidatorClient } from './clients/validator-client';
|
|
16
17
|
export { encodeJson, ByteArrayEncoding } from './lib/helpers';
|
|
17
18
|
export { NetworkOptimizer } from './network_optimizer';
|
|
18
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUztBQUNULGNBQWMsU0FBUyxDQUFDO0FBRXhCLHFCQUFxQjtBQUNyQixPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEtBQUssVUFBVSxNQUFNLGtCQUFrQixDQUFDO0FBQy9DLE9BQU8sS0FBSyxlQUFlLE1BQU0seUJBQXlCLENBQUM7QUFDM0QsT0FBTyxLQUFLLEtBQUssTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxLQUFLLFVBQVUsTUFBTSxrQkFBa0IsQ0FBQztBQUUvQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsT0FBTyxJQUFJLFdBQVcsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGNBQWMsSUFBSSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQyJ9
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AuthenticatorType } from '../clients/constants';
|
|
2
|
+
import { type Get } from '../clients/modules/get';
|
|
3
|
+
export declare const createNewRandomDydxWallet: () => Promise<{
|
|
4
|
+
privateKeyHex: string;
|
|
5
|
+
mnemonic: string;
|
|
6
|
+
publicKey: string;
|
|
7
|
+
address: string;
|
|
8
|
+
} | undefined>;
|
|
9
|
+
export declare const getAuthorizeNewTradingKeyArguments: ({ generatedWalletPubKey, }: {
|
|
10
|
+
generatedWalletPubKey: string;
|
|
11
|
+
}) => {
|
|
12
|
+
type: AuthenticatorType;
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
};
|
|
15
|
+
type Awaited<T> = T extends Promise<infer U> ? U : T;
|
|
16
|
+
export declare const getAuthorizedTradingKeysMetadata: (authorizedKeys: Awaited<ReturnType<Get["getAuthenticators"]>>["accountAuthenticators"]) => Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
publicKey: string;
|
|
19
|
+
address: string;
|
|
20
|
+
}>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=trading-key-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trading-key-utils.d.ts","sourceRoot":"","sources":["../../../../src/lib/trading-key-utils.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,iBAAiB,EAIlB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAKlD,eAAO,MAAM,yBAAyB,QAAa,OAAO,CACxD;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAwB5F,CAAC;AAIF,eAAO,MAAM,kCAAkC,GAAI,4BAEhD;IACD,qBAAqB,EAAE,MAAM,CAAC;CAC/B,KAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CA6C9C,CAAC;AAGF,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAIrD,eAAO,MAAM,gCAAgC,GAC3C,gBAAgB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,KACrF,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA+B1D,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
import { AuthenticatorType, TYPE_URL_BATCH_CANCEL, TYPE_URL_MSG_CANCEL_ORDER, TYPE_URL_MSG_PLACE_ORDER, } from '../clients/constants';
|
|
6
|
+
import LocalWallet from '../clients/modules/local-wallet';
|
|
7
|
+
import { BECH32_PREFIX } from './constants';
|
|
8
|
+
import { deriveHDKeyFromMnemonic } from './onboarding';
|
|
9
|
+
export const createNewRandomDydxWallet = async () => {
|
|
10
|
+
const mnemonic = generateMnemonic(wordlist, 128);
|
|
11
|
+
const { privateKey: privateKeyRaw } = deriveHDKeyFromMnemonic(mnemonic);
|
|
12
|
+
const wallet = await LocalWallet.fromMnemonic(mnemonic, BECH32_PREFIX);
|
|
13
|
+
const privateKeyHex = privateKeyRaw != null ? `0x${toHex(privateKeyRaw)}` : undefined;
|
|
14
|
+
const publicKey = wallet.pubKey;
|
|
15
|
+
const address = wallet.address;
|
|
16
|
+
if (privateKeyHex == null || publicKey == null || address == null) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
// 12 english words
|
|
21
|
+
mnemonic,
|
|
22
|
+
// toHex of the raw private key bits
|
|
23
|
+
privateKeyHex,
|
|
24
|
+
// base64, not hex
|
|
25
|
+
publicKey: publicKey.value,
|
|
26
|
+
// valid dydx address corresponding to the key pair
|
|
27
|
+
address,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
// arguments to authorize a given wallet public key to trade on behalf of the user.
|
|
31
|
+
// allows place order, cancel order, batch cancel on subaccount 0 only.
|
|
32
|
+
export const getAuthorizeNewTradingKeyArguments = ({ generatedWalletPubKey, }) => {
|
|
33
|
+
const wrapAndEncode64 = (s) => toBase64(new TextEncoder().encode(s));
|
|
34
|
+
const messageFilterSubAuth = [
|
|
35
|
+
{
|
|
36
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
37
|
+
config: wrapAndEncode64(TYPE_URL_MSG_PLACE_ORDER),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
41
|
+
config: wrapAndEncode64(TYPE_URL_MSG_CANCEL_ORDER),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
45
|
+
config: wrapAndEncode64(TYPE_URL_BATCH_CANCEL),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
const anyOfMessageFilterConfigB64 = wrapAndEncode64(JSON.stringify(messageFilterSubAuth));
|
|
49
|
+
const subAuth = [
|
|
50
|
+
{
|
|
51
|
+
type: AuthenticatorType.SIGNATURE_VERIFICATION,
|
|
52
|
+
config: generatedWalletPubKey,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: AuthenticatorType.ANY_OF,
|
|
56
|
+
config: anyOfMessageFilterConfigB64,
|
|
57
|
+
},
|
|
58
|
+
// we limit to cross markets to make it slightly harder to drain user funds on low liquidity markets with trading keys
|
|
59
|
+
// could undo this in the future if people are angry about it
|
|
60
|
+
{
|
|
61
|
+
type: AuthenticatorType.SUBACCOUNT_FILTER,
|
|
62
|
+
config: wrapAndEncode64('0'),
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
const jsonString = JSON.stringify(subAuth);
|
|
66
|
+
const encodedData = new TextEncoder().encode(jsonString);
|
|
67
|
+
const topLevelType = AuthenticatorType.ALL_OF;
|
|
68
|
+
return {
|
|
69
|
+
type: topLevelType,
|
|
70
|
+
data: encodedData,
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
const isTruthy = (n) => Boolean(n);
|
|
74
|
+
// just parses out keys that match the format created in getAuthorizeNewTradingKeyArguments
|
|
75
|
+
export const getAuthorizedTradingKeysMetadata = (authorizedKeys) => {
|
|
76
|
+
return authorizedKeys
|
|
77
|
+
.map(({ config, id, type }) => {
|
|
78
|
+
var _a;
|
|
79
|
+
if (type !== AuthenticatorType.ALL_OF) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const parsedConfig = JSON.parse(new TextDecoder().decode(config));
|
|
83
|
+
if (parsedConfig == null) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const publicKey = (_a = parsedConfig.find((t) => t.type === AuthenticatorType.SIGNATURE_VERIFICATION)) === null || _a === void 0 ? void 0 : _a.config;
|
|
87
|
+
if (publicKey == null || typeof publicKey !== 'string') {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const address = toBech32(BECH32_PREFIX, rawSecp256k1PubkeyToRawAddress(fromBase64(publicKey)));
|
|
91
|
+
return {
|
|
92
|
+
id: id.toString(),
|
|
93
|
+
publicKey,
|
|
94
|
+
address,
|
|
95
|
+
};
|
|
96
|
+
})
|
|
97
|
+
.filter(isTruthy);
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhZGluZy1rZXktdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3RyYWRpbmcta2V5LXV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN4RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRTFELE9BQU8sRUFFTCxpQkFBaUIsRUFDakIscUJBQXFCLEVBQ3JCLHlCQUF5QixFQUN6Qix3QkFBd0IsR0FDekIsTUFBTSxzQkFBc0IsQ0FBQztBQUU5QixPQUFPLFdBQVcsTUFBTSxpQ0FBaUMsQ0FBQztBQUMxRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzVDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV2RCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxLQUFLLElBRTVDLEVBQUU7SUFDRixNQUFNLFFBQVEsR0FBRyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDakQsTUFBTSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsR0FBRyx1QkFBdUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBRXZFLE1BQU0sYUFBYSxHQUFHLGFBQWEsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssS0FBSyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN0RixN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
|