@dydxprotocol/v4-client-js 1.0.4 → 1.0.6
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/__native__/__ios__/v4-native-client.js +175 -27
- package/build/examples/noble_example.d.ts +1 -0
- package/build/examples/noble_example.js +87 -0
- package/build/src/clients/modules/local-wallet.d.ts +1 -0
- package/build/src/clients/modules/local-wallet.js +2 -1
- package/build/src/clients/native.d.ts +4 -0
- package/build/src/clients/native.js +51 -3
- package/build/src/clients/noble-client.d.ts +15 -0
- package/build/src/clients/noble-client.js +63 -0
- package/build/src/index.d.ts +1 -0
- package/build/src/index.js +4 -2
- package/build/src/lib/constants.d.ts +1 -0
- package/build/src/lib/constants.js +3 -2
- package/examples/noble_example.ts +118 -0
- package/package.json +1 -1
- package/src/clients/modules/local-wallet.ts +2 -0
- package/src/clients/native.ts +64 -1
- package/src/clients/noble-client.ts +99 -0
- package/src/index.ts +1 -0
- package/src/lib/constants.ts +1 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { EncodeObject } from '@cosmjs/proto-signing';
|
|
2
|
+
import Long from 'long';
|
|
3
|
+
|
|
4
|
+
import { Network } from '../src/clients/constants';
|
|
5
|
+
import LocalWallet from '../src/clients/modules/local-wallet';
|
|
6
|
+
import { NobleClient } from '../src/clients/noble-client';
|
|
7
|
+
import { ValidatorClient } from '../src/clients/validator-client';
|
|
8
|
+
import { BECH32_PREFIX, NOBLE_BECH32_PREFIX } from '../src/lib/constants';
|
|
9
|
+
import { sleep } from '../src/lib/utils';
|
|
10
|
+
import { DYDX_TEST_MNEMONIC } from './constants';
|
|
11
|
+
|
|
12
|
+
async function test(): Promise<void> {
|
|
13
|
+
const dydxClient = await ValidatorClient.connect(
|
|
14
|
+
Network.testnet().validatorConfig,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const dydxWallet = await LocalWallet.fromMnemonic(
|
|
18
|
+
DYDX_TEST_MNEMONIC,
|
|
19
|
+
BECH32_PREFIX,
|
|
20
|
+
);
|
|
21
|
+
const nobleWallet = await LocalWallet.fromMnemonic(
|
|
22
|
+
DYDX_TEST_MNEMONIC,
|
|
23
|
+
NOBLE_BECH32_PREFIX,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const client = new NobleClient('https://rpc.testnet.noble.strange.love');
|
|
27
|
+
await client.connect(nobleWallet);
|
|
28
|
+
|
|
29
|
+
if (nobleWallet.address === undefined || dydxWallet.address === undefined) {
|
|
30
|
+
throw new Error('Wallet not found');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// IBC to noble
|
|
34
|
+
|
|
35
|
+
const ibcToNobleMsg: EncodeObject = {
|
|
36
|
+
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
|
|
37
|
+
value: {
|
|
38
|
+
sourcePort: 'transfer',
|
|
39
|
+
sourceChannel: 'channel-0',
|
|
40
|
+
token: {
|
|
41
|
+
denom:
|
|
42
|
+
'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5',
|
|
43
|
+
amount: '1000000',
|
|
44
|
+
},
|
|
45
|
+
sender: dydxWallet.address,
|
|
46
|
+
receiver: nobleWallet.address,
|
|
47
|
+
timeoutTimestamp: Long.fromNumber(
|
|
48
|
+
Math.floor(Date.now() / 1000) * 1e9 + 10 * 60 * 1e9,
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const msgs = [ibcToNobleMsg];
|
|
54
|
+
const encodeObjects: Promise<EncodeObject[]> = new Promise((resolve) => resolve(msgs),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await dydxClient.post.send(
|
|
58
|
+
dydxWallet,
|
|
59
|
+
() => {
|
|
60
|
+
return encodeObjects;
|
|
61
|
+
},
|
|
62
|
+
false,
|
|
63
|
+
undefined,
|
|
64
|
+
undefined,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
await sleep(30000);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const coins = await client.getAccountBalances();
|
|
71
|
+
console.log('Balances');
|
|
72
|
+
console.log(JSON.stringify(coins));
|
|
73
|
+
|
|
74
|
+
// IBC from noble
|
|
75
|
+
|
|
76
|
+
const ibcFromNobleMsg: EncodeObject = {
|
|
77
|
+
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
|
|
78
|
+
value: {
|
|
79
|
+
sourcePort: 'transfer',
|
|
80
|
+
sourceChannel: 'channel-21',
|
|
81
|
+
token: {
|
|
82
|
+
denom: 'uusdc',
|
|
83
|
+
amount: coins[0].amount,
|
|
84
|
+
},
|
|
85
|
+
sender: nobleWallet.address,
|
|
86
|
+
receiver: dydxWallet.address,
|
|
87
|
+
timeoutTimestamp: Long.fromNumber(
|
|
88
|
+
Math.floor(Date.now() / 1000) * 1e9 + 10 * 60 * 1e9,
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const fee = await client.simulateTransaction([ibcFromNobleMsg]);
|
|
93
|
+
|
|
94
|
+
ibcFromNobleMsg.value.token.amount = (parseInt(ibcFromNobleMsg.value.token.amount, 10) -
|
|
95
|
+
Math.floor(parseInt(fee.amount[0].amount, 10) * 1.4)).toString();
|
|
96
|
+
|
|
97
|
+
await client.send([ibcFromNobleMsg]);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(JSON.stringify(error.message));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await sleep(30000);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const coin = await client.getAccountBalance('uusdc');
|
|
106
|
+
console.log('Balance');
|
|
107
|
+
console.log(JSON.stringify(coin));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.log(JSON.stringify(error.message));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
test()
|
|
114
|
+
.then(() => {})
|
|
115
|
+
.catch((error) => {
|
|
116
|
+
console.log(error.message);
|
|
117
|
+
console.log(error);
|
|
118
|
+
});
|
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ export default class LocalWallet {
|
|
|
28
28
|
address?: string;
|
|
29
29
|
pubKey?: Secp256k1Pubkey;
|
|
30
30
|
signer?: TransactionSigner;
|
|
31
|
+
offlineSigner?: OfflineSigner;
|
|
31
32
|
|
|
32
33
|
static async fromOfflineSigner(signer:OfflineSigner): Promise<LocalWallet> {
|
|
33
34
|
const wallet = new LocalWallet();
|
|
@@ -42,6 +43,7 @@ export default class LocalWallet {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
async setSigner(signer: OfflineSigner): Promise<void> {
|
|
46
|
+
this.offlineSigner = signer;
|
|
45
47
|
const stargateClient = await SigningStargateClient.offline(
|
|
46
48
|
signer,
|
|
47
49
|
{
|
package/src/clients/native.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { Order_Side, Order_TimeInForce } from '@dydxprotocol/v4-proto/src/codege
|
|
|
8
8
|
import * as AuthModule from 'cosmjs-types/cosmos/auth/v1beta1/query';
|
|
9
9
|
import Long from 'long';
|
|
10
10
|
|
|
11
|
-
import { BECH32_PREFIX } from '../lib/constants';
|
|
11
|
+
import { BECH32_PREFIX, GAS_MULTIPLIER, NOBLE_BECH32_PREFIX } from '../lib/constants';
|
|
12
12
|
import { UserError } from '../lib/errors';
|
|
13
13
|
import { ByteArrayEncoding, encodeJson } from '../lib/helpers';
|
|
14
14
|
import { deriveHDKeyFromEthereumSignature } from '../lib/onboarding';
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from './constants';
|
|
20
20
|
import { FaucetClient } from './faucet-client';
|
|
21
21
|
import LocalWallet from './modules/local-wallet';
|
|
22
|
+
import { NobleClient } from './noble-client';
|
|
22
23
|
import { SubaccountInfo } from './subaccount';
|
|
23
24
|
import { OrderFlags } from './types';
|
|
24
25
|
|
|
@@ -29,6 +30,9 @@ declare global {
|
|
|
29
30
|
var faucetClient: FaucetClient | null;
|
|
30
31
|
// eslint-disable-next-line vars-on-top, no-var
|
|
31
32
|
var wallet: LocalWallet;
|
|
33
|
+
|
|
34
|
+
// eslint-disable-next-line vars-on-top, no-var
|
|
35
|
+
var nobleClient: NobleClient | undefined;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
export async function connectClient(
|
|
@@ -53,6 +57,7 @@ export async function connectNetwork(
|
|
|
53
57
|
validatorUrl,
|
|
54
58
|
chainId,
|
|
55
59
|
faucetUrl,
|
|
60
|
+
nobleValidatorUrl,
|
|
56
61
|
USDC_DENOM,
|
|
57
62
|
USDC_DECIMALS,
|
|
58
63
|
USDC_GAS_DENOM,
|
|
@@ -90,6 +95,7 @@ export async function connectNetwork(
|
|
|
90
95
|
} else {
|
|
91
96
|
globalThis.faucetClient = null;
|
|
92
97
|
}
|
|
98
|
+
globalThis.nobleClient = new NobleClient(nobleValidatorUrl);
|
|
93
99
|
return encodeJson(config);
|
|
94
100
|
} catch (e) {
|
|
95
101
|
return wrappedError(e);
|
|
@@ -101,6 +107,12 @@ export async function connectWallet(
|
|
|
101
107
|
): Promise<string> {
|
|
102
108
|
try {
|
|
103
109
|
globalThis.wallet = await LocalWallet.fromMnemonic(mnemonic, BECH32_PREFIX);
|
|
110
|
+
const nobleWallet = await LocalWallet.fromMnemonic(
|
|
111
|
+
mnemonic,
|
|
112
|
+
NOBLE_BECH32_PREFIX,
|
|
113
|
+
);
|
|
114
|
+
await globalThis.nobleClient?.connect(nobleWallet);
|
|
115
|
+
|
|
104
116
|
const address = globalThis.wallet.address!;
|
|
105
117
|
return encodeJson({ address });
|
|
106
118
|
} catch (e) {
|
|
@@ -988,3 +1000,54 @@ export async function getMarketPrice(
|
|
|
988
1000
|
return wrappedError(e);
|
|
989
1001
|
}
|
|
990
1002
|
}
|
|
1003
|
+
|
|
1004
|
+
export async function getNobleBalance(): Promise<String> {
|
|
1005
|
+
try {
|
|
1006
|
+
const client = globalThis.nobleClient;
|
|
1007
|
+
if (client === undefined || !client.isConnected) {
|
|
1008
|
+
throw new UserError(
|
|
1009
|
+
'client is not connected.',
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
const coin = await client.getAccountBalance('uusdc');
|
|
1013
|
+
return encodeJson(coin);
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
return wrappedError(error);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
export async function sendNobleIBC(squidPayload: string): Promise<String> {
|
|
1020
|
+
try {
|
|
1021
|
+
const client = globalThis.nobleClient;
|
|
1022
|
+
if (client === undefined || !client.isConnected) {
|
|
1023
|
+
throw new UserError(
|
|
1024
|
+
'client is not connected.',
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
const decode = (str: string): string => Buffer.from(str, 'base64').toString('binary');
|
|
1029
|
+
const decoded = decode(squidPayload);
|
|
1030
|
+
|
|
1031
|
+
const json = JSON.parse(decoded);
|
|
1032
|
+
|
|
1033
|
+
const ibcMsg: EncodeObject = {
|
|
1034
|
+
typeUrl: json.msgTypeUrl, // '/ibc.applications.transfer.v1.MsgTransfer',
|
|
1035
|
+
value: json.msg,
|
|
1036
|
+
};
|
|
1037
|
+
const fee = await client.simulateTransaction([ibcMsg]);
|
|
1038
|
+
|
|
1039
|
+
// take out fee from amount before sweeping
|
|
1040
|
+
const amount = parseInt(ibcMsg.value.token.amount, 10) -
|
|
1041
|
+
Math.floor(parseInt(fee.amount[0].amount, 10) * GAS_MULTIPLIER);
|
|
1042
|
+
|
|
1043
|
+
if (amount <= 0) {
|
|
1044
|
+
throw new UserError('noble balance does not cover fees');
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
ibcMsg.value.token.amount = amount.toString();
|
|
1048
|
+
const tx = await client.send([ibcMsg]);
|
|
1049
|
+
return encodeJson(tx);
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
return wrappedError(error);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { EncodeObject, Registry, Coin } from '@cosmjs/proto-signing';
|
|
2
|
+
import {
|
|
3
|
+
calculateFee,
|
|
4
|
+
DeliverTxResponse,
|
|
5
|
+
GasPrice,
|
|
6
|
+
StdFee,
|
|
7
|
+
defaultRegistryTypes,
|
|
8
|
+
SigningStargateClient,
|
|
9
|
+
} from '@cosmjs/stargate';
|
|
10
|
+
|
|
11
|
+
import { GAS_MULTIPLIER } from './constants';
|
|
12
|
+
import LocalWallet from './modules/local-wallet';
|
|
13
|
+
|
|
14
|
+
export class NobleClient {
|
|
15
|
+
private wallet?: LocalWallet;
|
|
16
|
+
private restEndpoint: string;
|
|
17
|
+
private stargateClient?: SigningStargateClient;
|
|
18
|
+
|
|
19
|
+
constructor(restEndpoint: string) {
|
|
20
|
+
this.restEndpoint = restEndpoint;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get isConnected(): boolean {
|
|
24
|
+
return Boolean(this.stargateClient);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async connect(
|
|
28
|
+
wallet: LocalWallet,
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
if (wallet?.offlineSigner === undefined) {
|
|
31
|
+
throw new Error('Wallet signer not found');
|
|
32
|
+
}
|
|
33
|
+
this.wallet = wallet;
|
|
34
|
+
this.stargateClient = await SigningStargateClient.connectWithSigner(
|
|
35
|
+
this.restEndpoint,
|
|
36
|
+
wallet.offlineSigner,
|
|
37
|
+
{ registry: new Registry(defaultRegistryTypes) },
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getAccountBalances(): Promise<readonly Coin[]> {
|
|
42
|
+
if (!this.stargateClient || this.wallet?.address === undefined) {
|
|
43
|
+
throw new Error('stargateClient not initialized');
|
|
44
|
+
}
|
|
45
|
+
return this.stargateClient.getAllBalances(this.wallet.address);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getAccountBalance(denom: string): Promise<Coin> {
|
|
49
|
+
if (!this.stargateClient || this.wallet?.address === undefined) {
|
|
50
|
+
throw new Error('stargateClient not initialized');
|
|
51
|
+
}
|
|
52
|
+
return this.stargateClient.getBalance(this.wallet.address, denom);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async send(
|
|
56
|
+
messages: EncodeObject[],
|
|
57
|
+
gasPrice: GasPrice = GasPrice.fromString('0.025uusdc'),
|
|
58
|
+
memo?: string,
|
|
59
|
+
): Promise<DeliverTxResponse> {
|
|
60
|
+
if (!this.stargateClient) {
|
|
61
|
+
throw new Error('NobleClient stargateClient not initialized');
|
|
62
|
+
}
|
|
63
|
+
if (this.wallet?.address === undefined) {
|
|
64
|
+
throw new Error('NobleClient wallet not initialized');
|
|
65
|
+
}
|
|
66
|
+
// Simulate to get the gas estimate
|
|
67
|
+
const fee = await this.simulateTransaction(messages, gasPrice, memo);
|
|
68
|
+
|
|
69
|
+
// Sign and broadcast the transaction
|
|
70
|
+
return this.stargateClient.signAndBroadcast(
|
|
71
|
+
this.wallet.address,
|
|
72
|
+
messages,
|
|
73
|
+
fee,
|
|
74
|
+
memo ?? '',
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async simulateTransaction(
|
|
79
|
+
messages: readonly EncodeObject[],
|
|
80
|
+
gasPrice: GasPrice = GasPrice.fromString('0.025uusdc'),
|
|
81
|
+
memo?: string,
|
|
82
|
+
): Promise<StdFee> {
|
|
83
|
+
if (!this.stargateClient) {
|
|
84
|
+
throw new Error('NobleClient stargateClient not initialized');
|
|
85
|
+
}
|
|
86
|
+
if (this.wallet?.address === undefined) {
|
|
87
|
+
throw new Error('NobleClient wallet not initialized');
|
|
88
|
+
}
|
|
89
|
+
// Get simulated response
|
|
90
|
+
const gasEstimate = await this.stargateClient.simulate(
|
|
91
|
+
this.wallet?.address,
|
|
92
|
+
messages,
|
|
93
|
+
memo,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Calculate and return the fee
|
|
97
|
+
return calculateFee(Math.floor(gasEstimate * GAS_MULTIPLIER), gasPrice);
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * as onboarding from './lib/onboarding';
|
|
|
9
9
|
export { default as LocalWallet } from './clients/modules/local-wallet';
|
|
10
10
|
export { SubaccountInfo as SubaccountClient } from './clients/subaccount';
|
|
11
11
|
export { CompositeClient } from './clients/composite-client';
|
|
12
|
+
export { NobleClient } from './clients/noble-client';
|
|
12
13
|
export { IndexerClient } from './clients/indexer-client';
|
|
13
14
|
export { ValidatorClient } from './clients/validator-client';
|
|
14
15
|
export { FaucetClient } from './clients/faucet-client';
|