genlayer 0.34.0 → 0.34.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/dist/index.js +13 -3
- package/package.json +11 -2
- package/.eslintignore +0 -2
- package/.github/workflows/cli-docs.yml +0 -121
- package/.github/workflows/publish-beta.yml +0 -41
- package/.github/workflows/publish.yml +0 -43
- package/.github/workflows/validate-code.yml +0 -47
- package/.prettierignore +0 -19
- package/.prettierrc +0 -12
- package/.release-it.json +0 -64
- package/CHANGELOG.md +0 -425
- package/CLAUDE.md +0 -55
- package/CONTRIBUTING.md +0 -117
- package/docker-compose.yml +0 -154
- package/docs/delegator-guide.md +0 -203
- package/docs/validator-guide.md +0 -329
- package/esbuild.config.dev.js +0 -17
- package/esbuild.config.js +0 -22
- package/esbuild.config.prod.js +0 -17
- package/eslint.config.js +0 -60
- package/renovate.json +0 -22
- package/src/commands/account/create.ts +0 -30
- package/src/commands/account/export.ts +0 -106
- package/src/commands/account/import.ts +0 -135
- package/src/commands/account/index.ts +0 -129
- package/src/commands/account/list.ts +0 -34
- package/src/commands/account/lock.ts +0 -39
- package/src/commands/account/remove.ts +0 -30
- package/src/commands/account/send.ts +0 -162
- package/src/commands/account/show.ts +0 -74
- package/src/commands/account/unlock.ts +0 -56
- package/src/commands/account/use.ts +0 -21
- package/src/commands/config/getSetReset.ts +0 -51
- package/src/commands/config/index.ts +0 -30
- package/src/commands/contracts/call.ts +0 -39
- package/src/commands/contracts/code.ts +0 -33
- package/src/commands/contracts/deploy.ts +0 -157
- package/src/commands/contracts/index.ts +0 -86
- package/src/commands/contracts/schema.ts +0 -31
- package/src/commands/contracts/write.ts +0 -49
- package/src/commands/general/index.ts +0 -45
- package/src/commands/general/init.ts +0 -179
- package/src/commands/general/start.ts +0 -116
- package/src/commands/general/stop.ts +0 -26
- package/src/commands/localnet/index.ts +0 -100
- package/src/commands/localnet/validators.ts +0 -269
- package/src/commands/network/index.ts +0 -29
- package/src/commands/network/setNetwork.ts +0 -77
- package/src/commands/scaffold/index.ts +0 -16
- package/src/commands/scaffold/new.ts +0 -34
- package/src/commands/staking/StakingAction.ts +0 -279
- package/src/commands/staking/delegatorClaim.ts +0 -41
- package/src/commands/staking/delegatorExit.ts +0 -56
- package/src/commands/staking/delegatorJoin.ts +0 -44
- package/src/commands/staking/index.ts +0 -357
- package/src/commands/staking/setIdentity.ts +0 -78
- package/src/commands/staking/setOperator.ts +0 -46
- package/src/commands/staking/stakingInfo.ts +0 -584
- package/src/commands/staking/validatorClaim.ts +0 -43
- package/src/commands/staking/validatorDeposit.ts +0 -48
- package/src/commands/staking/validatorExit.ts +0 -63
- package/src/commands/staking/validatorHistory.ts +0 -298
- package/src/commands/staking/validatorJoin.ts +0 -47
- package/src/commands/staking/validatorPrime.ts +0 -73
- package/src/commands/staking/wizard.ts +0 -809
- package/src/commands/transactions/appeal.ts +0 -39
- package/src/commands/transactions/index.ts +0 -39
- package/src/commands/transactions/receipt.ts +0 -90
- package/src/commands/update/index.ts +0 -25
- package/src/commands/update/ollama.ts +0 -103
- package/src/lib/actions/BaseAction.ts +0 -299
- package/src/lib/clients/jsonRpcClient.ts +0 -41
- package/src/lib/clients/system.ts +0 -73
- package/src/lib/config/ConfigFileManager.ts +0 -194
- package/src/lib/config/KeychainManager.ts +0 -89
- package/src/lib/config/simulator.ts +0 -68
- package/src/lib/config/text.ts +0 -2
- package/src/lib/errors/missingRequirement.ts +0 -9
- package/src/lib/errors/versionRequired.ts +0 -9
- package/src/lib/interfaces/ISimulatorService.ts +0 -37
- package/src/lib/services/simulator.ts +0 -351
- package/src/types/node-fetch.d.ts +0 -1
- package/tests/actions/appeal.test.ts +0 -99
- package/tests/actions/call.test.ts +0 -94
- package/tests/actions/code.test.ts +0 -87
- package/tests/actions/create.test.ts +0 -65
- package/tests/actions/deploy.test.ts +0 -420
- package/tests/actions/getSetReset.test.ts +0 -88
- package/tests/actions/init.test.ts +0 -467
- package/tests/actions/lock.test.ts +0 -86
- package/tests/actions/new.test.ts +0 -80
- package/tests/actions/ollama.test.ts +0 -193
- package/tests/actions/receipt.test.ts +0 -261
- package/tests/actions/schema.test.ts +0 -94
- package/tests/actions/setNetwork.test.ts +0 -160
- package/tests/actions/staking.test.ts +0 -279
- package/tests/actions/start.test.ts +0 -235
- package/tests/actions/stop.test.ts +0 -77
- package/tests/actions/unlock.test.ts +0 -139
- package/tests/actions/validators.test.ts +0 -750
- package/tests/actions/write.test.ts +0 -102
- package/tests/commands/account.test.ts +0 -146
- package/tests/commands/appeal.test.ts +0 -58
- package/tests/commands/call.test.ts +0 -78
- package/tests/commands/code.test.ts +0 -69
- package/tests/commands/config.test.ts +0 -54
- package/tests/commands/deploy.test.ts +0 -83
- package/tests/commands/init.test.ts +0 -101
- package/tests/commands/localnet.test.ts +0 -131
- package/tests/commands/network.test.ts +0 -60
- package/tests/commands/new.test.ts +0 -68
- package/tests/commands/receipt.test.ts +0 -142
- package/tests/commands/schema.test.ts +0 -67
- package/tests/commands/staking.test.ts +0 -329
- package/tests/commands/stop.test.ts +0 -27
- package/tests/commands/up.test.ts +0 -105
- package/tests/commands/update.test.ts +0 -45
- package/tests/commands/write.test.ts +0 -76
- package/tests/index.test.ts +0 -56
- package/tests/libs/baseAction.test.ts +0 -516
- package/tests/libs/configFileManager.test.ts +0 -117
- package/tests/libs/jsonRpcClient.test.ts +0 -59
- package/tests/libs/keychainManager.test.ts +0 -156
- package/tests/libs/system.test.ts +0 -148
- package/tests/services/simulator.test.ts +0 -705
- package/tests/utils.ts +0 -13
- package/tsconfig.json +0 -120
- package/vitest.config.ts +0 -12
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
import inquirer from "inquirer";
|
|
2
|
-
import { rpcClient } from "../../lib/clients/jsonRpcClient";
|
|
3
|
-
import { BaseAction } from "../../lib/actions/BaseAction";
|
|
4
|
-
|
|
5
|
-
export interface ValidatorOptions {
|
|
6
|
-
address?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface UpdateValidatorOptions {
|
|
10
|
-
address: string;
|
|
11
|
-
stake?: string;
|
|
12
|
-
provider?: string;
|
|
13
|
-
model?: string;
|
|
14
|
-
config?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface CreateRandomValidatorsOptions {
|
|
18
|
-
count: string;
|
|
19
|
-
providers: string[];
|
|
20
|
-
models: string[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface CreateValidatorOptions {
|
|
24
|
-
stake: string;
|
|
25
|
-
config?: string;
|
|
26
|
-
model?: string;
|
|
27
|
-
provider?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class ValidatorsAction extends BaseAction {
|
|
31
|
-
public async getValidator(options: ValidatorOptions): Promise<void> {
|
|
32
|
-
try {
|
|
33
|
-
if (options.address) {
|
|
34
|
-
this.startSpinner(`Fetching validator with address: ${options.address}`);
|
|
35
|
-
|
|
36
|
-
const result = await rpcClient.request({
|
|
37
|
-
method: "sim_getValidator",
|
|
38
|
-
params: [options.address],
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
this.succeedSpinner(`Successfully fetched validator with address: ${options.address}`, result.result);
|
|
42
|
-
} else {
|
|
43
|
-
this.startSpinner(`Fetching all validators...`);
|
|
44
|
-
|
|
45
|
-
const result = await rpcClient.request({
|
|
46
|
-
method: "sim_getAllValidators",
|
|
47
|
-
params: [],
|
|
48
|
-
});
|
|
49
|
-
this.succeedSpinner('Successfully fetched all validators.', result.result)
|
|
50
|
-
}
|
|
51
|
-
} catch (error) {
|
|
52
|
-
this.failSpinner("Error fetching validators", error);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public async deleteValidator(options: ValidatorOptions): Promise<void> {
|
|
57
|
-
try {
|
|
58
|
-
if (options.address) {
|
|
59
|
-
await this.confirmPrompt(`This command will delete the validator with the address: ${options.address}. Do you want to continue?`);
|
|
60
|
-
this.startSpinner(`Deleting validator with address: ${options.address}`);
|
|
61
|
-
|
|
62
|
-
const result = await rpcClient.request({
|
|
63
|
-
method: "sim_deleteValidator",
|
|
64
|
-
params: [options.address],
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
this.succeedSpinner(`Deleted Address: ${result.result}`);
|
|
68
|
-
} else {
|
|
69
|
-
await this.confirmPrompt(`This command will delete all validators. Do you want to continue?`);
|
|
70
|
-
this.startSpinner("Deleting all validators...");
|
|
71
|
-
|
|
72
|
-
await rpcClient.request({
|
|
73
|
-
method: "sim_deleteAllValidators",
|
|
74
|
-
params: [],
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
this.succeedSpinner("Successfully deleted all validators");
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
this.failSpinner("Error deleting validators", error);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public async countValidators(): Promise<void> {
|
|
85
|
-
try {
|
|
86
|
-
this.startSpinner("Counting all validators...");
|
|
87
|
-
|
|
88
|
-
const result = await rpcClient.request({
|
|
89
|
-
method: "sim_countValidators",
|
|
90
|
-
params: [],
|
|
91
|
-
});
|
|
92
|
-
this.succeedSpinner(`Total Validators: ${result.result}`);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
this.failSpinner("Error counting validators", error);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
public async updateValidator(options: UpdateValidatorOptions): Promise<void> {
|
|
99
|
-
try {
|
|
100
|
-
this.startSpinner(`Fetching validator with address: ${options.address}...`);
|
|
101
|
-
const currentValidator = await rpcClient.request({
|
|
102
|
-
method: "sim_getValidator",
|
|
103
|
-
params: [options.address],
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
this.log("Current Validator Details:", currentValidator.result);
|
|
107
|
-
|
|
108
|
-
const parsedStake = options.stake
|
|
109
|
-
? parseInt(options.stake, 10)
|
|
110
|
-
: currentValidator.result.stake;
|
|
111
|
-
|
|
112
|
-
if (isNaN(parsedStake) || parsedStake < 0) {
|
|
113
|
-
return this.failSpinner("Invalid stake value. Stake must be a positive integer.");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const updatedValidator = {
|
|
117
|
-
address: options.address,
|
|
118
|
-
stake: options.stake || currentValidator.result.stake,
|
|
119
|
-
provider: options.provider || currentValidator.result.provider,
|
|
120
|
-
model: options.model || currentValidator.result.model,
|
|
121
|
-
config: options.config ? JSON.parse(options.config) : currentValidator.result.config,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
this.log("Updated Validator Details:", updatedValidator);
|
|
125
|
-
|
|
126
|
-
this.setSpinnerText('Updating Validator...');
|
|
127
|
-
|
|
128
|
-
const result = await rpcClient.request({
|
|
129
|
-
method: "sim_updateValidator",
|
|
130
|
-
params: [
|
|
131
|
-
updatedValidator.address,
|
|
132
|
-
updatedValidator.stake,
|
|
133
|
-
updatedValidator.provider,
|
|
134
|
-
updatedValidator.model,
|
|
135
|
-
updatedValidator.config,
|
|
136
|
-
],
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
this.succeedSpinner("Validator successfully updated", result.result);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
this.failSpinner("Error updating validator", error);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
public async createRandomValidators(options: CreateRandomValidatorsOptions): Promise<void> {
|
|
146
|
-
try {
|
|
147
|
-
const count = parseInt(options.count, 10);
|
|
148
|
-
if (isNaN(count) || count < 1) {
|
|
149
|
-
return this.logError("Invalid count. Please provide a positive integer.");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
this.startSpinner(`Creating ${count} random validator(s)...`);
|
|
153
|
-
this.log(`Providers: ${options.providers.length > 0 ? options.providers.join(", ") : "All"}`);
|
|
154
|
-
this.log(`Models: ${options.models.length > 0 ? options.models.join(", ") : "All"}`);
|
|
155
|
-
|
|
156
|
-
const result = await rpcClient.request({
|
|
157
|
-
method: "sim_createRandomValidators",
|
|
158
|
-
params: [count, 1, 10, options.providers, options.models],
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
this.succeedSpinner("Random validators successfully created", result.result);
|
|
162
|
-
} catch (error) {
|
|
163
|
-
this.failSpinner("Error creating random validators", error);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
public async createValidator(options: CreateValidatorOptions): Promise<void> {
|
|
168
|
-
try {
|
|
169
|
-
const stake = parseInt(options.stake, 10);
|
|
170
|
-
if (isNaN(stake) || stake < 1) {
|
|
171
|
-
return this.logError("Invalid stake. Please provide a positive integer.");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (options.model && !options.provider) {
|
|
175
|
-
return this.logError("You must specify a provider if using a model.");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this.startSpinner("Fetching available providers and models...");
|
|
179
|
-
|
|
180
|
-
const providersAndModels = await rpcClient.request({
|
|
181
|
-
method: "sim_getProvidersAndModels",
|
|
182
|
-
params: [],
|
|
183
|
-
});
|
|
184
|
-
this.stopSpinner();
|
|
185
|
-
|
|
186
|
-
if (!providersAndModels.result || providersAndModels.result.length === 0) {
|
|
187
|
-
return this.logError("No providers or models available.");
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const availableProviders = [
|
|
191
|
-
...new Map(
|
|
192
|
-
providersAndModels.result
|
|
193
|
-
.filter((entry: any) => entry.is_available)
|
|
194
|
-
.map((entry: any) => [entry.provider, entry])
|
|
195
|
-
).values(),
|
|
196
|
-
];
|
|
197
|
-
|
|
198
|
-
let provider = options.provider
|
|
199
|
-
|
|
200
|
-
if(!provider){
|
|
201
|
-
const { selectedProvider } = await inquirer.prompt([
|
|
202
|
-
{
|
|
203
|
-
type: "list",
|
|
204
|
-
name: "selectedProvider",
|
|
205
|
-
message: "Select a provider:",
|
|
206
|
-
choices: availableProviders.map((entry: any) => entry.provider),
|
|
207
|
-
},
|
|
208
|
-
]);
|
|
209
|
-
|
|
210
|
-
provider = selectedProvider;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const availableModels = providersAndModels.result.filter(
|
|
214
|
-
(entry: any) => entry.provider === provider && entry.is_model_available
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
if (availableModels.length === 0) {
|
|
218
|
-
return this.logError("No models available for the selected provider.");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let model = options.model;
|
|
222
|
-
|
|
223
|
-
if(!model){
|
|
224
|
-
const { selectedModel } = await inquirer.prompt([
|
|
225
|
-
{
|
|
226
|
-
type: "list",
|
|
227
|
-
name: "selectedModel",
|
|
228
|
-
message: "Select a model:",
|
|
229
|
-
choices: availableModels.map((entry: any) => entry.model),
|
|
230
|
-
},
|
|
231
|
-
]);
|
|
232
|
-
|
|
233
|
-
model = selectedModel;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const modelDetails = availableModels.find(
|
|
237
|
-
(entry: any) => entry.model === model
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
if (!modelDetails) {
|
|
241
|
-
return this.logError("Selected model details not found.");
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const config = options.config ? JSON.parse(options.config) : modelDetails.config;
|
|
245
|
-
const params = [
|
|
246
|
-
stake,
|
|
247
|
-
modelDetails.provider,
|
|
248
|
-
modelDetails.model,
|
|
249
|
-
config,
|
|
250
|
-
modelDetails.plugin,
|
|
251
|
-
modelDetails.plugin_config,
|
|
252
|
-
]
|
|
253
|
-
|
|
254
|
-
this.log("Validator details:", params);
|
|
255
|
-
this.startSpinner('Creating validator...');
|
|
256
|
-
|
|
257
|
-
const result = await rpcClient.request({
|
|
258
|
-
method: "sim_createValidator",
|
|
259
|
-
params,
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
this.succeedSpinner("Validator successfully created:", result.result);
|
|
263
|
-
} catch (error) {
|
|
264
|
-
this.failSpinner("Error creating validator", error);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {Command} from "commander";
|
|
2
|
-
import {NetworkActions} from "./setNetwork";
|
|
3
|
-
|
|
4
|
-
export function initializeNetworkCommands(program: Command) {
|
|
5
|
-
const networkActions = new NetworkActions();
|
|
6
|
-
|
|
7
|
-
const network = program.command("network").description("Network configuration");
|
|
8
|
-
|
|
9
|
-
// genlayer network set [name]
|
|
10
|
-
network
|
|
11
|
-
.command("set")
|
|
12
|
-
.description("Set the network to use")
|
|
13
|
-
.argument("[network]", "The network to set")
|
|
14
|
-
.action((networkName?: string) => networkActions.setNetwork(networkName));
|
|
15
|
-
|
|
16
|
-
// genlayer network info
|
|
17
|
-
network
|
|
18
|
-
.command("info")
|
|
19
|
-
.description("Show current network configuration and contract addresses")
|
|
20
|
-
.action(() => networkActions.showInfo());
|
|
21
|
-
|
|
22
|
-
// genlayer network list
|
|
23
|
-
network
|
|
24
|
-
.command("list")
|
|
25
|
-
.description("List available networks")
|
|
26
|
-
.action(() => networkActions.listNetworks());
|
|
27
|
-
|
|
28
|
-
return program;
|
|
29
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import {BaseAction, BUILT_IN_NETWORKS, resolveNetwork} from "../../lib/actions/BaseAction";
|
|
2
|
-
import inquirer, {DistinctQuestion} from "inquirer";
|
|
3
|
-
|
|
4
|
-
const networks = Object.entries(BUILT_IN_NETWORKS).map(([alias, network]) => ({
|
|
5
|
-
name: network.name,
|
|
6
|
-
alias,
|
|
7
|
-
value: network,
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
export class NetworkActions extends BaseAction {
|
|
11
|
-
constructor() {
|
|
12
|
-
super();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async showInfo(): Promise<void> {
|
|
16
|
-
const storedNetwork = this.getConfigByKey("network") || "localnet";
|
|
17
|
-
const network = resolveNetwork(storedNetwork);
|
|
18
|
-
|
|
19
|
-
const info: Record<string, string> = {
|
|
20
|
-
alias: storedNetwork,
|
|
21
|
-
name: network.name,
|
|
22
|
-
chainId: network.id?.toString() || "unknown",
|
|
23
|
-
rpc: network.rpcUrls?.default?.http?.[0] || "unknown",
|
|
24
|
-
mainContract: network.consensusMainContract?.address || "not set",
|
|
25
|
-
stakingContract: network.stakingContract?.address || "not set",
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
if (network.blockExplorers?.default?.url) {
|
|
29
|
-
info.explorer = network.blockExplorers.default.url;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this.succeedSpinner("Current network", info);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async listNetworks(): Promise<void> {
|
|
36
|
-
const currentNetwork = this.getConfigByKey("network") || "localnet";
|
|
37
|
-
|
|
38
|
-
console.log("");
|
|
39
|
-
for (const net of networks) {
|
|
40
|
-
const marker = net.alias === currentNetwork ? "*" : " ";
|
|
41
|
-
console.log(`${marker} ${net.alias.padEnd(16)} ${net.name}`);
|
|
42
|
-
}
|
|
43
|
-
console.log("");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async setNetwork(networkName?: string): Promise<void> {
|
|
47
|
-
if (networkName || networkName === "") {
|
|
48
|
-
if (!networks.some(n => n.name === networkName || n.alias === networkName)) {
|
|
49
|
-
this.failSpinner(`Network ${networkName} not found`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const selectedNetwork = networks.find(n => n.name === networkName || n.alias === networkName);
|
|
53
|
-
if (!selectedNetwork) {
|
|
54
|
-
this.failSpinner(`Network ${networkName} not found`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
this.writeConfig("network", selectedNetwork.alias);
|
|
58
|
-
this.succeedSpinner(`Network successfully set to ${selectedNetwork.name}`);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const networkQuestions: DistinctQuestion[] = [
|
|
63
|
-
{
|
|
64
|
-
type: "list",
|
|
65
|
-
name: "selectedNetwork",
|
|
66
|
-
message: "Select which network do you want to use:",
|
|
67
|
-
choices: networks.map(n => ({name: n.name, value: n.alias})),
|
|
68
|
-
},
|
|
69
|
-
];
|
|
70
|
-
const networkAnswer = await inquirer.prompt(networkQuestions);
|
|
71
|
-
const selectedAlias = networkAnswer.selectedNetwork;
|
|
72
|
-
const selectedNetwork = networks.find(n => n.alias === selectedAlias)!;
|
|
73
|
-
|
|
74
|
-
this.writeConfig("network", selectedAlias);
|
|
75
|
-
this.succeedSpinner(`Network successfully set to ${selectedNetwork.name}`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { NewAction } from "./new";
|
|
3
|
-
|
|
4
|
-
export function initializeScaffoldCommands(program: Command) {
|
|
5
|
-
program
|
|
6
|
-
.command("new <projectName>")
|
|
7
|
-
.description("Create a new GenLayer project using the default template")
|
|
8
|
-
.option("--path <directory>", "Specify the directory for the new project", ".")
|
|
9
|
-
.option("--overwrite", "Overwrite existing directory if it exists", false)
|
|
10
|
-
.action(async (projectName, options) => {
|
|
11
|
-
const newProjectAction = new NewAction();
|
|
12
|
-
await newProjectAction.createProject(projectName, options);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
return program;
|
|
16
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import fs from "fs-extra";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import { BaseAction } from "../../lib/actions/BaseAction";
|
|
5
|
-
|
|
6
|
-
export class NewAction extends BaseAction {
|
|
7
|
-
private templatePath: string;
|
|
8
|
-
|
|
9
|
-
constructor() {
|
|
10
|
-
super();
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const basePath = path.resolve(path.dirname(__filename), "..");
|
|
13
|
-
this.templatePath = path.join(basePath, "templates", "default");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async createProject(projectName: string, options: { path: string; overwrite: boolean }) {
|
|
17
|
-
const targetPath = path.resolve(options.path, projectName);
|
|
18
|
-
|
|
19
|
-
if (fs.existsSync(targetPath) && !options.overwrite) {
|
|
20
|
-
return this.failSpinner(
|
|
21
|
-
`Project directory "${targetPath}" already exists. Use --overwrite to replace it.`
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this.startSpinner(`Creating new GenLayer project: ${projectName}`);
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
fs.copySync(this.templatePath, targetPath);
|
|
29
|
-
this.succeedSpinner(`Project "${projectName}" created successfully at ${targetPath}`);
|
|
30
|
-
} catch (error) {
|
|
31
|
-
this.failSpinner(`Error creating project "${projectName}"`, error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import {BaseAction, BUILT_IN_NETWORKS, resolveNetwork} from "../../lib/actions/BaseAction";
|
|
2
|
-
import {createClient, createAccount, formatStakingAmount, parseStakingAmount, abi} from "genlayer-js";
|
|
3
|
-
import type {GenLayerClient, GenLayerChain, Address} from "genlayer-js/types";
|
|
4
|
-
import {readFileSync, existsSync} from "fs";
|
|
5
|
-
import {ethers, ZeroAddress} from "ethers";
|
|
6
|
-
import {createPublicClient, createWalletClient, http, type PublicClient, type WalletClient, type Chain, type Account} from "viem";
|
|
7
|
-
import {privateKeyToAccount} from "viem/accounts";
|
|
8
|
-
|
|
9
|
-
// Extended ABI for tree traversal (not in SDK)
|
|
10
|
-
const STAKING_TREE_ABI = [
|
|
11
|
-
{
|
|
12
|
-
name: "validatorsRoot",
|
|
13
|
-
type: "function",
|
|
14
|
-
stateMutability: "view",
|
|
15
|
-
inputs: [],
|
|
16
|
-
outputs: [{name: "", type: "address"}],
|
|
17
|
-
},
|
|
18
|
-
] as const;
|
|
19
|
-
|
|
20
|
-
// Re-export for use by other staking commands
|
|
21
|
-
export {BUILT_IN_NETWORKS};
|
|
22
|
-
|
|
23
|
-
export interface StakingConfig {
|
|
24
|
-
rpc?: string;
|
|
25
|
-
stakingAddress?: string;
|
|
26
|
-
network?: string;
|
|
27
|
-
account?: string;
|
|
28
|
-
password?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class StakingAction extends BaseAction {
|
|
32
|
-
private _stakingClient: GenLayerClient<GenLayerChain> | null = null;
|
|
33
|
-
private _passwordOverride: string | undefined;
|
|
34
|
-
|
|
35
|
-
constructor() {
|
|
36
|
-
super();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private getNetwork(config: StakingConfig): GenLayerChain {
|
|
40
|
-
// Priority: --network option > global config > localnet default
|
|
41
|
-
if (config.network) {
|
|
42
|
-
const network = BUILT_IN_NETWORKS[config.network];
|
|
43
|
-
if (!network) {
|
|
44
|
-
throw new Error(`Unknown network: ${config.network}. Available: ${Object.keys(BUILT_IN_NETWORKS).join(", ")}`);
|
|
45
|
-
}
|
|
46
|
-
return {...network};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return resolveNetwork(this.getConfig().network);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
protected async getStakingClient(config: StakingConfig): Promise<GenLayerClient<GenLayerChain>> {
|
|
53
|
-
if (!this._stakingClient) {
|
|
54
|
-
// Set account override if provided
|
|
55
|
-
if (config.account) {
|
|
56
|
-
this.accountOverride = config.account;
|
|
57
|
-
}
|
|
58
|
-
if (config.password) {
|
|
59
|
-
this._passwordOverride = config.password;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const network = this.getNetwork(config);
|
|
63
|
-
|
|
64
|
-
// Override staking address if provided
|
|
65
|
-
if (config.stakingAddress) {
|
|
66
|
-
network.stakingContract = {
|
|
67
|
-
address: config.stakingAddress,
|
|
68
|
-
abi: abi.STAKING_ABI,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const privateKey = await this.getPrivateKeyForStaking();
|
|
73
|
-
const account = createAccount(privateKey as `0x${string}`);
|
|
74
|
-
|
|
75
|
-
this._stakingClient = createClient({
|
|
76
|
-
chain: network,
|
|
77
|
-
endpoint: config.rpc,
|
|
78
|
-
account,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
return this._stakingClient;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
protected async getReadOnlyStakingClient(config: StakingConfig): Promise<GenLayerClient<GenLayerChain>> {
|
|
85
|
-
// Set account override if provided
|
|
86
|
-
if (config.account) {
|
|
87
|
-
this.accountOverride = config.account;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const network = this.getNetwork(config);
|
|
91
|
-
|
|
92
|
-
if (config.stakingAddress) {
|
|
93
|
-
network.stakingContract = {
|
|
94
|
-
address: config.stakingAddress,
|
|
95
|
-
abi: abi.STAKING_ABI,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const accountName = this.resolveAccountName();
|
|
100
|
-
const keystorePath = this.getKeystorePath(accountName);
|
|
101
|
-
|
|
102
|
-
if (!existsSync(keystorePath)) {
|
|
103
|
-
throw new Error(`Account '${accountName}' not found. Run 'genlayer account create --name ${accountName}' first.`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const keystoreData = JSON.parse(readFileSync(keystorePath, "utf-8"));
|
|
107
|
-
const addr = keystoreData.address as string;
|
|
108
|
-
const normalizedAddress = (addr.startsWith("0x") ? addr : `0x${addr}`) as Address;
|
|
109
|
-
|
|
110
|
-
return createClient({
|
|
111
|
-
chain: network,
|
|
112
|
-
endpoint: config.rpc,
|
|
113
|
-
account: normalizedAddress,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
private async getPrivateKeyForStaking(): Promise<string> {
|
|
118
|
-
const accountName = this.resolveAccountName();
|
|
119
|
-
const keystorePath = this.getKeystorePath(accountName);
|
|
120
|
-
|
|
121
|
-
if (!existsSync(keystorePath)) {
|
|
122
|
-
throw new Error(`Account '${accountName}' not found. Run 'genlayer account create --name ${accountName}' first.`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const keystoreJson = readFileSync(keystorePath, "utf-8");
|
|
126
|
-
const keystoreData = JSON.parse(keystoreJson);
|
|
127
|
-
|
|
128
|
-
if (!this.isValidKeystoreFormat(keystoreData)) {
|
|
129
|
-
throw new Error("Invalid keystore format.");
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const cachedKey = await this.keychainManager.getPrivateKey(accountName);
|
|
133
|
-
if (cachedKey) {
|
|
134
|
-
// Verify cached key matches keystore address - safety check
|
|
135
|
-
const tempAccount = createAccount(cachedKey as `0x${string}`);
|
|
136
|
-
const cachedAddress = tempAccount.address.toLowerCase();
|
|
137
|
-
const keystoreAddress = `0x${keystoreData.address.toLowerCase().replace(/^0x/, '')}`;
|
|
138
|
-
|
|
139
|
-
if (cachedAddress !== keystoreAddress) {
|
|
140
|
-
// Cached key doesn't match keystore - invalidate it
|
|
141
|
-
await this.keychainManager.removePrivateKey(accountName);
|
|
142
|
-
// Fall through to prompt for password
|
|
143
|
-
} else {
|
|
144
|
-
return cachedKey;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
let password: string;
|
|
149
|
-
if (this._passwordOverride) {
|
|
150
|
-
password = this._passwordOverride;
|
|
151
|
-
} else {
|
|
152
|
-
this.stopSpinner();
|
|
153
|
-
password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
|
|
154
|
-
}
|
|
155
|
-
this.startSpinner("Unlocking account...");
|
|
156
|
-
|
|
157
|
-
const wallet = await ethers.Wallet.fromEncryptedJson(keystoreJson, password);
|
|
158
|
-
return wallet.privateKey;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
protected parseAmount(amount: string): bigint {
|
|
162
|
-
return parseStakingAmount(amount);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
protected formatAmount(amount: bigint): string {
|
|
166
|
-
return formatStakingAmount(amount);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
protected async getSignerAddress(): Promise<Address> {
|
|
170
|
-
const accountName = this.resolveAccountName();
|
|
171
|
-
const keystorePath = this.getKeystorePath(accountName);
|
|
172
|
-
if (!existsSync(keystorePath)) {
|
|
173
|
-
throw new Error(`Account '${accountName}' not found.`);
|
|
174
|
-
}
|
|
175
|
-
const keystoreData = JSON.parse(readFileSync(keystorePath, "utf-8"));
|
|
176
|
-
const addr = keystoreData.address as string;
|
|
177
|
-
return (addr.startsWith("0x") ? addr : `0x${addr}`) as Address;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Get viem clients for direct contract interactions (e.g., ValidatorWallet calls)
|
|
182
|
-
* Future: can be extended to support hardware wallets
|
|
183
|
-
*/
|
|
184
|
-
protected async getViemClients(config: StakingConfig): Promise<{
|
|
185
|
-
walletClient: WalletClient<any, Chain, Account>;
|
|
186
|
-
publicClient: PublicClient;
|
|
187
|
-
signerAddress: Address;
|
|
188
|
-
}> {
|
|
189
|
-
if (config.account) {
|
|
190
|
-
this.accountOverride = config.account;
|
|
191
|
-
}
|
|
192
|
-
if (config.password) {
|
|
193
|
-
this._passwordOverride = config.password;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const network = this.getNetwork(config);
|
|
197
|
-
const rpcUrl = config.rpc || network.rpcUrls.default.http[0];
|
|
198
|
-
|
|
199
|
-
const privateKey = await this.getPrivateKeyForStaking();
|
|
200
|
-
const account = privateKeyToAccount(privateKey as `0x${string}`);
|
|
201
|
-
|
|
202
|
-
const publicClient = createPublicClient({
|
|
203
|
-
chain: network,
|
|
204
|
-
transport: http(rpcUrl),
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
const walletClient = createWalletClient({
|
|
208
|
-
chain: network,
|
|
209
|
-
transport: http(rpcUrl),
|
|
210
|
-
account,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
walletClient,
|
|
215
|
-
publicClient,
|
|
216
|
-
signerAddress: account.address as Address,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Get all validators by traversing the validator tree.
|
|
222
|
-
* This finds ALL validators including those not yet active/primed.
|
|
223
|
-
*/
|
|
224
|
-
protected async getAllValidatorsFromTree(config: StakingConfig): Promise<Address[]> {
|
|
225
|
-
const network = this.getNetwork(config);
|
|
226
|
-
const rpcUrl = config.rpc || network.rpcUrls.default.http[0];
|
|
227
|
-
const stakingAddress = config.stakingAddress || network.stakingContract?.address;
|
|
228
|
-
|
|
229
|
-
if (!stakingAddress) {
|
|
230
|
-
throw new Error("Staking contract address not configured");
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const publicClient = createPublicClient({
|
|
234
|
-
chain: network,
|
|
235
|
-
transport: http(rpcUrl),
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
// Get the root of the validator tree
|
|
239
|
-
const root = await publicClient.readContract({
|
|
240
|
-
address: stakingAddress as `0x${string}`,
|
|
241
|
-
abi: STAKING_TREE_ABI,
|
|
242
|
-
functionName: "validatorsRoot",
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
if (root === ZeroAddress) {
|
|
246
|
-
return [];
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const validators: Address[] = [];
|
|
250
|
-
const stack: string[] = [root as string];
|
|
251
|
-
const visited = new Set<string>();
|
|
252
|
-
|
|
253
|
-
// Use validatorView from SDK's ABI (has left/right fields)
|
|
254
|
-
while (stack.length > 0) {
|
|
255
|
-
const addr = stack.pop()!;
|
|
256
|
-
|
|
257
|
-
if (addr === ZeroAddress || visited.has(addr.toLowerCase())) continue;
|
|
258
|
-
visited.add(addr.toLowerCase());
|
|
259
|
-
|
|
260
|
-
validators.push(addr as Address);
|
|
261
|
-
|
|
262
|
-
const info = await publicClient.readContract({
|
|
263
|
-
address: stakingAddress as `0x${string}`,
|
|
264
|
-
abi: abi.STAKING_ABI,
|
|
265
|
-
functionName: "validatorView",
|
|
266
|
-
args: [addr as `0x${string}`],
|
|
267
|
-
}) as {left: string; right: string};
|
|
268
|
-
|
|
269
|
-
if (info.left !== ZeroAddress) {
|
|
270
|
-
stack.push(info.left);
|
|
271
|
-
}
|
|
272
|
-
if (info.right !== ZeroAddress) {
|
|
273
|
-
stack.push(info.right);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return validators;
|
|
278
|
-
}
|
|
279
|
-
}
|