wative 1.2.7 → 1.2.10
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/package.json +23 -23
- package/src/account.ts +0 -864
- package/src/assets.ts +0 -399
- package/src/chain.ts +0 -28
- package/src/config.ts +0 -2074
- package/src/daemon-watcher.js +0 -181
- package/src/home_page.ts +0 -36
- package/src/index.d.ts +0 -12
- package/src/index.ts +0 -53
- package/src/network.ts +0 -819
- package/src/ssh/client.ts +0 -389
- package/src/ssh/config_manager.ts +0 -304
- package/src/ssh/index.ts +0 -66
- package/src/ssh/service_manager.ts +0 -685
- package/src/ssh/types.ts +0 -50
- package/src/ssh/utils.ts +0 -89
- package/src/ssh/wative_server.ts +0 -534
- package/src/tools.ts +0 -923
- package/src/tx_gas_utils.ts +0 -119
- package/src/utils.ts +0 -916
- package/src/wallet-cli.ts +0 -39
- package/src/wative.ts +0 -633
- package/src/web3.ts +0 -415
package/src/ssh/types.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
type SubAccountMessageParams = {
|
|
2
|
-
rootAccount: string,
|
|
3
|
-
chainId: string,
|
|
4
|
-
startIndex?: number,
|
|
5
|
-
endIndex?: number
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
type SignMessageParams = {
|
|
9
|
-
txParams: any,
|
|
10
|
-
rpcUrl: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type SSHServiceConfig = {
|
|
14
|
-
name: string;
|
|
15
|
-
description?: string;
|
|
16
|
-
ssh: {
|
|
17
|
-
listen: string;
|
|
18
|
-
port: number;
|
|
19
|
-
log: {
|
|
20
|
-
size: number;
|
|
21
|
-
backups: number;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
keystore: {
|
|
25
|
-
path: string;
|
|
26
|
-
allowed_keystores: string[];
|
|
27
|
-
};
|
|
28
|
-
clients: {
|
|
29
|
-
name: string;
|
|
30
|
-
public_key_path: string;
|
|
31
|
-
allowed_keystores: string[];
|
|
32
|
-
}[];
|
|
33
|
-
server_keys: {
|
|
34
|
-
private_key_path: string;
|
|
35
|
-
passphrase: string;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type ServiceInstance = {
|
|
40
|
-
config: SSHServiceConfig;
|
|
41
|
-
passwords: { [keystoreId: string]: string };
|
|
42
|
-
server: any;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export {
|
|
46
|
-
SubAccountMessageParams,
|
|
47
|
-
SignMessageParams,
|
|
48
|
-
SSHServiceConfig,
|
|
49
|
-
ServiceInstance
|
|
50
|
-
}
|
package/src/ssh/utils.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as ini from 'ini';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
|
-
import { getNetworkInfo } from '../account';
|
|
6
|
-
import { batchGetKeystoreSlugByAccountName } from '../utils';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Check the existence of the file
|
|
11
|
-
* @filePath
|
|
12
|
-
*/
|
|
13
|
-
const checkFileExistence = (filePath: string) => {
|
|
14
|
-
filePath = filePath.trim()
|
|
15
|
-
let isExists = fs.existsSync(filePath)
|
|
16
|
-
if (!isExists) {
|
|
17
|
-
throw new Error('File not exists')
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function sleep(time = 0) {
|
|
22
|
-
return new Promise((resolve, reject) => {
|
|
23
|
-
setTimeout(() => {
|
|
24
|
-
resolve(true)
|
|
25
|
-
}, time)
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const createSSHKeyPair = async () => {
|
|
30
|
-
const configDir = "/etc/wative";
|
|
31
|
-
const idRsaServerPublicKeyPath = path.join(configDir, 'id_rsa_server.pub');
|
|
32
|
-
const idRsaServerPrivateKeyPath = path.join(configDir, 'id_rsa_server');
|
|
33
|
-
|
|
34
|
-
if (!fs.existsSync(idRsaServerPublicKeyPath) || !fs.existsSync(idRsaServerPrivateKeyPath)) {
|
|
35
|
-
console.log('Generating SSH key pair...');
|
|
36
|
-
execSync(`ssh-keygen -t rsa -f ${idRsaServerPrivateKeyPath} -N 'wative_server'`, { stdio: 'inherit' });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const idRsaDetakePublicKeyPath = path.join(configDir, 'id_rsa_detake.pub');
|
|
40
|
-
const idRsaDetakePrivateKeyPath = path.join(configDir, 'id_rsa_detake');
|
|
41
|
-
|
|
42
|
-
if (!fs.existsSync(idRsaDetakePublicKeyPath) || !fs.existsSync(idRsaDetakePrivateKeyPath)) {
|
|
43
|
-
console.log('Generating SSH key pair...');
|
|
44
|
-
execSync(`ssh-keygen -t rsa -f ${idRsaDetakePrivateKeyPath} -N 'wative_detake'`, { stdio: 'inherit' });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const getAndGenerateConfig = async (keystorePath: string) => {
|
|
50
|
-
const configDir = "/etc/wative";
|
|
51
|
-
if (!fs.existsSync(configDir)) {
|
|
52
|
-
fs.mkdirSync(configDir);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
await createSSHKeyPair();
|
|
56
|
-
const configPath = path.join(configDir, 'config.ini');
|
|
57
|
-
if (!fs.existsSync(configPath)) {
|
|
58
|
-
const networks = getNetworkInfo(keystorePath);
|
|
59
|
-
const account_name_list = networks.accounts;
|
|
60
|
-
const keystore_slug_list = batchGetKeystoreSlugByAccountName(account_name_list);
|
|
61
|
-
const keystore: any = {
|
|
62
|
-
path: keystorePath,
|
|
63
|
-
allowed_keystores: keystore_slug_list,
|
|
64
|
-
}
|
|
65
|
-
const ssh: any = {
|
|
66
|
-
listen: '127.0.0.1',
|
|
67
|
-
port: 5678,
|
|
68
|
-
log: {
|
|
69
|
-
size: 10485760,
|
|
70
|
-
backups: 3
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const config = {
|
|
74
|
-
keystore,
|
|
75
|
-
ssh,
|
|
76
|
-
}
|
|
77
|
-
let text = ini.stringify(config);
|
|
78
|
-
fs.writeFileSync(configPath, text);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const config = ini.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
82
|
-
return config;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export {
|
|
86
|
-
checkFileExistence,
|
|
87
|
-
sleep,
|
|
88
|
-
getAndGenerateConfig,
|
|
89
|
-
}
|
package/src/ssh/wative_server.ts
DELETED
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
import * as path from "path";
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
import { utils, Server } from 'ssh2';
|
|
4
|
-
import { timingSafeEqual } from 'crypto';
|
|
5
|
-
import { checkFileExistence } from './utils';
|
|
6
|
-
import { SignMessageParams, SubAccountMessageParams } from './types';
|
|
7
|
-
import * as log4js from "log4js";
|
|
8
|
-
import { ethers } from 'ethers';
|
|
9
|
-
|
|
10
|
-
const { WativeCore } = require("wative-core");
|
|
11
|
-
const { Connection, PublicKey, VersionedTransaction, VersionedMessage } = require("@solana/web3.js");
|
|
12
|
-
const bs58 = require("bs58");
|
|
13
|
-
const { Keypair, TransactionMessage, ComputeBudgetInstruction, TransactionInstruction, ComputeBudgetProgram } = require("@solana/web3.js");
|
|
14
|
-
const { Wallet } = require("@coral-xyz/anchor");
|
|
15
|
-
log4js.configure({
|
|
16
|
-
appenders: {
|
|
17
|
-
file: {
|
|
18
|
-
type: 'file',
|
|
19
|
-
filename: process.env.HOME + '/.wative/logs/wative.log',
|
|
20
|
-
maxLogSize: 10485760,
|
|
21
|
-
backups: 3,
|
|
22
|
-
compress: true,
|
|
23
|
-
keepFileExt: true,
|
|
24
|
-
layout: {
|
|
25
|
-
type: 'pattern',
|
|
26
|
-
pattern: '%d{yyyy-MM-dd hh:mm:ss.SSS} [%p] %c - %m'
|
|
27
|
-
},
|
|
28
|
-
encoding: 'utf-8'
|
|
29
|
-
},
|
|
30
|
-
console: { type: 'console' }
|
|
31
|
-
},
|
|
32
|
-
categories: {
|
|
33
|
-
default: { appenders: ['file', 'console'], level: 'info' }
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const logger = log4js.getLogger("file");
|
|
38
|
-
logger.level = "info";
|
|
39
|
-
|
|
40
|
-
export class WativeWielderServer {
|
|
41
|
-
private wativeCore: any;
|
|
42
|
-
private _allowedAppIds: Buffer[] = [];
|
|
43
|
-
private _allowedPubKeys: any[] = [];
|
|
44
|
-
private _allowedKeystoreIds: string[][] = [];
|
|
45
|
-
|
|
46
|
-
private _idRsaPrivatePath: string;
|
|
47
|
-
private _idRsaPassphrase: string | undefined;
|
|
48
|
-
|
|
49
|
-
private _keystoreDirectoryPath: string;
|
|
50
|
-
private _sessionIdAppIdMap: any = {};
|
|
51
|
-
|
|
52
|
-
public constructor(
|
|
53
|
-
idRsaPrivatePath: string,
|
|
54
|
-
idRsaPassphrase: string | undefined,
|
|
55
|
-
|
|
56
|
-
allowedAppIds: string[],
|
|
57
|
-
allowedPublicKeyPath: string[],
|
|
58
|
-
allowedKeystoreIds: string[][],
|
|
59
|
-
|
|
60
|
-
keystoreDirectoryPath: string,
|
|
61
|
-
keystoreIds: string[],
|
|
62
|
-
passwords: string[],
|
|
63
|
-
) {
|
|
64
|
-
checkFileExistence(idRsaPrivatePath);
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
allowedAppIds.length === 0 ||
|
|
68
|
-
allowedPublicKeyPath.length === 0 ||
|
|
69
|
-
allowedKeystoreIds.length === 0 ||
|
|
70
|
-
allowedAppIds.length !== allowedPublicKeyPath.length ||
|
|
71
|
-
allowedAppIds.length !== allowedKeystoreIds.length
|
|
72
|
-
) {
|
|
73
|
-
throw new Error('WativeWielderServer:: constructor: Invaild AllowedApp');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
for (let i = 0; i < allowedKeystoreIds.length; i++) {
|
|
77
|
-
for (let j = 0; j < allowedKeystoreIds[i].length; j++) {
|
|
78
|
-
const keystoreId = allowedKeystoreIds[i][j];
|
|
79
|
-
|
|
80
|
-
if (!keystoreIds.includes(keystoreId)) {
|
|
81
|
-
throw new Error('WativeWielderServer:: constructor: Invaild AllowedKeystoreIds');
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
for (let allowedAppId of allowedAppIds) {
|
|
87
|
-
this._allowedAppIds.push(
|
|
88
|
-
Buffer.from(allowedAppId)
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
for (let _allowedPublicKeyFilePath of allowedPublicKeyPath) {
|
|
93
|
-
let _parsedKey = utils.parseKey(readFileSync(_allowedPublicKeyFilePath));
|
|
94
|
-
this._allowedPubKeys.push(_parsedKey)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
this.wativeCore = new WativeCore(keystoreDirectoryPath, keystoreIds, passwords);
|
|
98
|
-
|
|
99
|
-
this._idRsaPrivatePath = idRsaPrivatePath;
|
|
100
|
-
this._idRsaPassphrase = idRsaPassphrase;
|
|
101
|
-
this._allowedKeystoreIds = allowedKeystoreIds;
|
|
102
|
-
|
|
103
|
-
this._keystoreDirectoryPath = keystoreDirectoryPath;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public listen(host: string, port: number) {
|
|
107
|
-
new Server({
|
|
108
|
-
hostKeys: [{
|
|
109
|
-
key: readFileSync(this._idRsaPrivatePath),
|
|
110
|
-
passphrase: this._idRsaPassphrase
|
|
111
|
-
}]
|
|
112
|
-
}, (client: any) => {
|
|
113
|
-
client.on('authentication', (ctx: any) => {
|
|
114
|
-
let allowed = true;
|
|
115
|
-
if (this)
|
|
116
|
-
if (!this.checkValue(Buffer.from(ctx.username), 'appId')) {
|
|
117
|
-
allowed = false;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (ctx.method === 'publickey' && allowed) {
|
|
121
|
-
let allowedAppIndex = this.getBytesIndex(Buffer.from(ctx.username), this._allowedAppIds);
|
|
122
|
-
|
|
123
|
-
let allowedPubKey = this._allowedPubKeys[allowedAppIndex];
|
|
124
|
-
|
|
125
|
-
if (ctx.key.algo !== allowedPubKey.type
|
|
126
|
-
|| !this.checkValue(ctx.key.data, 'publicKey')
|
|
127
|
-
|| (ctx.signature && allowedPubKey.verify(ctx.blob, ctx.signature, ctx.hashAlgo) !== true)) {
|
|
128
|
-
return ctx.reject();
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
return ctx.reject();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (allowed) {
|
|
135
|
-
const sessionID = client._protocol._kex.sessionID.toString('hex');
|
|
136
|
-
this._sessionIdAppIdMap[sessionID] = Buffer.from(ctx.username);
|
|
137
|
-
ctx.accept();
|
|
138
|
-
} else {
|
|
139
|
-
ctx.reject();
|
|
140
|
-
}
|
|
141
|
-
}).on('ready', () => {
|
|
142
|
-
|
|
143
|
-
client.on('session', (accept: any, reject: any) => {
|
|
144
|
-
const session = accept();
|
|
145
|
-
session.once('exec', async (accept: any, reject: any, info: any) => {
|
|
146
|
-
const sessionID = client._protocol._kex.sessionID.toString('hex');
|
|
147
|
-
const result = await this.web3Request(sessionID, info.command);
|
|
148
|
-
const stream = accept();
|
|
149
|
-
if (!stream) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (!JSON.stringify(result)) {
|
|
154
|
-
stream.write("ssh2 connect error");
|
|
155
|
-
stream.exit(0);
|
|
156
|
-
stream.end();
|
|
157
|
-
} else {
|
|
158
|
-
stream.write(JSON.stringify(result));
|
|
159
|
-
stream.exit(0);
|
|
160
|
-
stream.end();
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
});
|
|
164
|
-
}).on('close', () => {
|
|
165
|
-
logger.info('Client disconnected');
|
|
166
|
-
}).on('error', (err: any) => {
|
|
167
|
-
logger.error('err: ', err.message);
|
|
168
|
-
});
|
|
169
|
-
}).listen(port, host, function () {
|
|
170
|
-
logger.info('Listening on port ' + port);
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private async web3Request(sessionID: string, message: string) {
|
|
175
|
-
try {
|
|
176
|
-
const appId = this._sessionIdAppIdMap[sessionID];
|
|
177
|
-
const appIndex = this.getBytesIndex(appId, this._allowedAppIds);
|
|
178
|
-
if (appIndex < 0) {
|
|
179
|
-
return { status: false, msg: 'app not found' };
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
let messageData = JSON.parse(message);
|
|
183
|
-
logger.info("sign message: ", message);
|
|
184
|
-
let _messageMethod: string = messageData.method;
|
|
185
|
-
let _keystoreId: string = messageData.keystoreId || messageData.params.keystoreId;
|
|
186
|
-
let _chainId: string = messageData.chainId || messageData.params.chainId;
|
|
187
|
-
|
|
188
|
-
const allowedKeystoreIds = this._allowedKeystoreIds[appIndex];
|
|
189
|
-
if (!allowedKeystoreIds.includes(_keystoreId)) {
|
|
190
|
-
return { status: false, msg: 'keystore not allowed' };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
let _data: any;
|
|
194
|
-
if (_messageMethod === "get_root_account") {
|
|
195
|
-
_data = this.getRootAccount(_keystoreId, _chainId);
|
|
196
|
-
// _data = this.wativeCore.account.getRootAccounts(_keystoreId);
|
|
197
|
-
|
|
198
|
-
} else if (_messageMethod === "get_sub_account") {
|
|
199
|
-
let _message: SubAccountMessageParams = messageData.params;
|
|
200
|
-
|
|
201
|
-
_data = this.getSubAccount(_keystoreId, _message.chainId, _message?.startIndex, _message?.endIndex);
|
|
202
|
-
} else if (_messageMethod === "sign") {
|
|
203
|
-
let _message: SignMessageParams = messageData.params;
|
|
204
|
-
try {
|
|
205
|
-
_data = await this.wativeCore.account.signTransaction(_message.txParams.from, _message.txParams, _message.rpcUrl);
|
|
206
|
-
} catch (err: any) {
|
|
207
|
-
logger.error("sign error: ", err.message);
|
|
208
|
-
return { status: false, msg: err.msg };
|
|
209
|
-
}
|
|
210
|
-
} else if (_messageMethod === "sign_and_send") {
|
|
211
|
-
let _message: SignMessageParams = messageData.params;
|
|
212
|
-
try {
|
|
213
|
-
let txHash = await this.wativeCore.account.signAndSendTx(_message.txParams, _message.rpcUrl);
|
|
214
|
-
_data = {
|
|
215
|
-
transactionHash: txHash
|
|
216
|
-
}
|
|
217
|
-
} catch (err: any) {
|
|
218
|
-
return { status: false, msg: err.msg };
|
|
219
|
-
}
|
|
220
|
-
} else if (_messageMethod === "solana_sign") {
|
|
221
|
-
try {
|
|
222
|
-
let _message = messageData.params;
|
|
223
|
-
_data = await this.signSolanaTransaction(_message.txParams.from, _message.txParams.data, _message.txParams.lookup_tables, _message.rpcUrl, _message.priority_fee);
|
|
224
|
-
} catch (err: any) {
|
|
225
|
-
logger.error("sign error: ", err.message);
|
|
226
|
-
return { status: false, msg: err.msg };
|
|
227
|
-
}
|
|
228
|
-
} else if (_messageMethod === "solana_send") {
|
|
229
|
-
try {
|
|
230
|
-
let _message = messageData.params;
|
|
231
|
-
_data = await this.sendSignedSolanaTransaction(_message.txParams.from, _message.txParams.signature, _message.txParams.data, _message.rpcUrl);
|
|
232
|
-
} catch (err: any) {
|
|
233
|
-
logger.error("sign error: ", err.message);
|
|
234
|
-
return { status: false, msg: err.msg };
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
} else if (_messageMethod === "sign_message") {
|
|
238
|
-
try {
|
|
239
|
-
let _message = messageData.params;
|
|
240
|
-
logger.debug("sign message: ", _message);
|
|
241
|
-
_data = await this.signMessage(_message.account, _message.message);
|
|
242
|
-
} catch (err: any) {
|
|
243
|
-
logger.error("sign error: ", err.message);
|
|
244
|
-
return { status: false, msg: err.msg };
|
|
245
|
-
}
|
|
246
|
-
} else if (_messageMethod === "sign_typed_data") {
|
|
247
|
-
try {
|
|
248
|
-
let _message = messageData.params;
|
|
249
|
-
logger.debug("sign message: ", _message);
|
|
250
|
-
_data = await this.signTypedData(_message.account, _message.domain, _message.types_name, _message.types, _message.message)
|
|
251
|
-
} catch (err: any) {
|
|
252
|
-
logger.error("sign error: ", err.message);
|
|
253
|
-
return { status: false, msg: err.msg };
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
return { status: false, msg: 'message method not find' };
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return { status: true, data: _data };
|
|
260
|
-
} catch (err: any) {
|
|
261
|
-
logger.error("sign error: ", err.message);
|
|
262
|
-
return { status: false, msg: err.msg };
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
private checkValue(input: Buffer, checkTypes: string) {
|
|
267
|
-
|
|
268
|
-
if (checkTypes !== 'appId' && checkTypes !== 'publicKey') {
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
let allowedSize = this._allowedAppIds.length;
|
|
273
|
-
for (let i = 0; i < allowedSize; i++) {
|
|
274
|
-
let allowed: Buffer;
|
|
275
|
-
if (checkTypes === 'appId') {
|
|
276
|
-
allowed = this._allowedAppIds[i];
|
|
277
|
-
} else {
|
|
278
|
-
allowed = this._allowedPubKeys[i].getPublicSSH();
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const autoReject = (input.length !== allowed.length);
|
|
282
|
-
if (autoReject) {
|
|
283
|
-
allowed = input;
|
|
284
|
-
}
|
|
285
|
-
const isMatch = timingSafeEqual(input, allowed);
|
|
286
|
-
|
|
287
|
-
if (!autoReject && isMatch) {
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
private getBytesIndex(buf: Buffer, bufList: Buffer[]) {
|
|
294
|
-
let bufSize = bufList.length;
|
|
295
|
-
|
|
296
|
-
for (let i = 0; i < bufSize; i++) {
|
|
297
|
-
if (buf.length === bufList[i].length && timingSafeEqual(buf, bufList[i])) {
|
|
298
|
-
return i;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return -1;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
private getRootAccount(keystoreId: string, chainId: string) {
|
|
306
|
-
const keystore_path = path.resolve(this._keystoreDirectoryPath, `accounts/${keystoreId}.json`);
|
|
307
|
-
let keystore_info: any = readFileSync(keystore_path);
|
|
308
|
-
keystore_info = JSON.parse(keystore_info.toString());
|
|
309
|
-
|
|
310
|
-
let chainType = this.getChainType(chainId);
|
|
311
|
-
|
|
312
|
-
let root_address;
|
|
313
|
-
if (chainType === "SOLANA") {
|
|
314
|
-
root_address = keystore_info.data[0].ciphertexts.solana.address;
|
|
315
|
-
} else {
|
|
316
|
-
root_address = keystore_info.data[0].ciphertexts.evm.address;
|
|
317
|
-
}
|
|
318
|
-
return [{
|
|
319
|
-
id: 0,
|
|
320
|
-
address: root_address,
|
|
321
|
-
children: keystore_info.data.length,
|
|
322
|
-
type: "M"
|
|
323
|
-
}];
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private getChainType(chainId: string) {
|
|
327
|
-
if (chainId === "901" || chainId === "902" || chainId === "903") {
|
|
328
|
-
return "SOLANA";
|
|
329
|
-
}
|
|
330
|
-
return "EVM";
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
private getSubAccount(keystoreId: string, chainId: string, startIndex?: number, endIndex?: number) {
|
|
334
|
-
const keystore_path = path.resolve(this._keystoreDirectoryPath, `accounts/${keystoreId}.json`);
|
|
335
|
-
let keystore_info: any = readFileSync(keystore_path);
|
|
336
|
-
keystore_info = JSON.parse(keystore_info.toString());
|
|
337
|
-
|
|
338
|
-
let keystore_info_len = keystore_info.data.length;
|
|
339
|
-
let _endIndex = keystore_info_len - 1;
|
|
340
|
-
if (endIndex && endIndex < _endIndex) {
|
|
341
|
-
_endIndex = endIndex;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
let _startIndex = 0;
|
|
345
|
-
if (startIndex && startIndex > 0) {
|
|
346
|
-
_startIndex = startIndex;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (_startIndex > _endIndex) {
|
|
350
|
-
return [];
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
let chainType = this.getChainType(chainId);
|
|
354
|
-
let result: any = [];
|
|
355
|
-
for (let i = _startIndex; i <= _endIndex; i++) {
|
|
356
|
-
result.push(keystore_info.data[i].ciphertexts[chainType.toLocaleLowerCase()].address);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return result;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
private async signMessage(account: string, message: string) {
|
|
363
|
-
let signature = await this.wativeCore.account.signMessage(account, message);
|
|
364
|
-
console.log(signature);
|
|
365
|
-
return signature;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
private async signTypedData(account: string, message_domain: string, message_types_name: string, message_types: string, message_data: string) {
|
|
369
|
-
let domain = JSON.parse(message_domain);
|
|
370
|
-
let types = JSON.parse(message_types);
|
|
371
|
-
let data = JSON.parse(message_data);
|
|
372
|
-
|
|
373
|
-
console.log(domain);
|
|
374
|
-
console.log(types);
|
|
375
|
-
console.log(data);
|
|
376
|
-
let pkl = this.wativeCore.account.showPrivateKey(account);
|
|
377
|
-
let wallet: any = new ethers.Wallet(pkl);
|
|
378
|
-
let signature = await wallet.signTypedData(domain, {
|
|
379
|
-
[message_types_name]: types
|
|
380
|
-
}, data);
|
|
381
|
-
|
|
382
|
-
console.log(signature);
|
|
383
|
-
return {
|
|
384
|
-
"status": true,
|
|
385
|
-
"output": signature
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
private async signSolanaTransaction(from: string, data: string, lookup_table_addresses: any, rpc_url: string, prioritization_fee: any) {
|
|
390
|
-
let connection = new Connection(rpc_url);
|
|
391
|
-
|
|
392
|
-
let lookup_table_list: any = [];
|
|
393
|
-
if (lookup_table_addresses) {
|
|
394
|
-
for (let lookup_table_address of lookup_table_addresses) {
|
|
395
|
-
let lookup_table = (await connection.getAddressLookupTable(new PublicKey(lookup_table_address))).value;
|
|
396
|
-
lookup_table_list.push(lookup_table);
|
|
397
|
-
await sleep(1000);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
let versionedMessage = VersionedMessage.deserialize(Uint8Array.from(Buffer.from(data, "hex")));
|
|
402
|
-
let decompiled_transaction_message = TransactionMessage.decompile(versionedMessage);
|
|
403
|
-
decompiled_transaction_message.instructions.push(
|
|
404
|
-
ComputeBudgetProgram.setComputeUnitLimit({
|
|
405
|
-
units: 2000000
|
|
406
|
-
})
|
|
407
|
-
);
|
|
408
|
-
decompiled_transaction_message.instructions.push(
|
|
409
|
-
ComputeBudgetProgram.setComputeUnitPrice({
|
|
410
|
-
microLamports: 1000
|
|
411
|
-
})
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
versionedMessage = decompiled_transaction_message.compileToV0Message(lookup_table_list);
|
|
415
|
-
versionedMessage.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
416
|
-
|
|
417
|
-
await sleep(3000);
|
|
418
|
-
let versionedTransaction = new VersionedTransaction(versionedMessage);
|
|
419
|
-
let pkl = this.wativeCore.account.showPrivateKey(from);
|
|
420
|
-
const owner = Keypair.fromSecretKey(new Uint8Array(bs58.decode(pkl)));
|
|
421
|
-
const wallet = new Wallet(owner);
|
|
422
|
-
|
|
423
|
-
let simulate_transaction_result = await connection.simulateTransaction(versionedTransaction);
|
|
424
|
-
if (!simulate_transaction_result || !simulate_transaction_result.value || simulate_transaction_result.value.unitsConsumed === 0 || simulate_transaction_result.value.err) {
|
|
425
|
-
return {
|
|
426
|
-
status: false,
|
|
427
|
-
output: simulate_transaction_result.value.err
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
let message_instruction_length = decompiled_transaction_message.instructions.length;
|
|
432
|
-
let units_consumed = Math.trunc(simulate_transaction_result.value.unitsConsumed * 1.2);
|
|
433
|
-
decompiled_transaction_message.instructions[message_instruction_length - 2] = ComputeBudgetProgram.setComputeUnitLimit({
|
|
434
|
-
units: units_consumed
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
if (!prioritization_fee || prioritization_fee == "null") {
|
|
438
|
-
try {
|
|
439
|
-
prioritization_fee = await this.getPrioritizationFee(rpc_url);
|
|
440
|
-
} catch (err) {
|
|
441
|
-
prioritization_fee = 200000;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (prioritization_fee < 10000) {
|
|
446
|
-
prioritization_fee = 10000;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (prioritization_fee > 500000) {
|
|
450
|
-
prioritization_fee = 500000;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
decompiled_transaction_message.instructions[message_instruction_length - 1] = ComputeBudgetProgram.setComputeUnitPrice({
|
|
454
|
-
microLamports: prioritization_fee
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
versionedMessage = decompiled_transaction_message.compileToV0Message(lookup_table_list);
|
|
458
|
-
await sleep(1000);
|
|
459
|
-
versionedMessage.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
460
|
-
versionedTransaction = new VersionedTransaction(versionedMessage);
|
|
461
|
-
|
|
462
|
-
versionedTransaction.feePayer = wallet.publicKey;
|
|
463
|
-
await sleep(3000);
|
|
464
|
-
let signedTransaction = await this.wativeCore.account.signTransaction(from, versionedTransaction, rpc_url);
|
|
465
|
-
let new_versioned_transaction = new VersionedTransaction(signedTransaction.output.message, signedTransaction.output.signatures);
|
|
466
|
-
let new_message = new_versioned_transaction.message.serialize();
|
|
467
|
-
new_message = Buffer.from(new_message).toString("hex");
|
|
468
|
-
|
|
469
|
-
let tx_hash = bs58.encode(signedTransaction.output.signatures[0]);
|
|
470
|
-
return {
|
|
471
|
-
status: true,
|
|
472
|
-
output: {
|
|
473
|
-
transactionHash: tx_hash,
|
|
474
|
-
message: new_message,
|
|
475
|
-
compute_units: simulate_transaction_result.value.unitsConsumed.toString()
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
private async sendSignedSolanaTransaction(from: string, signature: string, data: string, rpc_url: string) {
|
|
481
|
-
let signatures = [
|
|
482
|
-
bs58.decode(signature)
|
|
483
|
-
];
|
|
484
|
-
|
|
485
|
-
let versionedMessage = VersionedMessage.deserialize(Uint8Array.from(Buffer.from(data, "hex")));
|
|
486
|
-
let versionedTransaction = new VersionedTransaction(versionedMessage, signatures);
|
|
487
|
-
|
|
488
|
-
return await this.wativeCore.account.sendSignedTransaction(from, versionedTransaction, rpc_url);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
private async getPrioritizationFee(rpc_url: string) {
|
|
492
|
-
let program_id = new PublicKey("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4");
|
|
493
|
-
const connection = new Connection(rpc_url, "confirmed");
|
|
494
|
-
let signatures_info: any = await connection.getSignaturesForAddress(program_id, { limit: 5 });
|
|
495
|
-
await sleep(2000);
|
|
496
|
-
|
|
497
|
-
let signatures: any = [];
|
|
498
|
-
for (let i = 0; i < signatures_info.length; i++) {
|
|
499
|
-
signatures.push(signatures_info[i].signature);
|
|
500
|
-
}
|
|
501
|
-
let transaction: any = await connection.getParsedTransactions(signatures, {
|
|
502
|
-
maxSupportedTransactionVersion: 0,
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
let total_prioritization_fee = 0;
|
|
506
|
-
for (let i = 0; i < transaction.length; i++) {
|
|
507
|
-
let instructions_list = transaction[i].transaction.message.instructions;
|
|
508
|
-
for (let j = 0; j < instructions_list.length; j++) {
|
|
509
|
-
if (instructions_list[j].programId.toBase58() === "ComputeBudget111111111111111111111111111111") {
|
|
510
|
-
let data = instructions_list[j].data;
|
|
511
|
-
try {
|
|
512
|
-
let instruction = new TransactionInstruction({
|
|
513
|
-
keys: [],
|
|
514
|
-
programId: new PublicKey("ComputeBudget111111111111111111111111111111"),
|
|
515
|
-
data: Buffer.from(bs58.decode(data))
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
let { microLamports } = ComputeBudgetInstruction.decodeSetComputeUnitPrice(instruction)
|
|
519
|
-
total_prioritization_fee += Number(microLamports);
|
|
520
|
-
continue;
|
|
521
|
-
} catch (error) { }
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
return Math.ceil(total_prioritization_fee / 5)
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
export const sleep = (ms: number) => {
|
|
531
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
export default WativeWielderServer;
|