genlayer 0.38.8 → 0.38.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.
Files changed (205) hide show
  1. package/.eslintignore +2 -0
  2. package/.github/workflows/cli-docs.yml +124 -0
  3. package/.github/workflows/publish.yml +55 -0
  4. package/.github/workflows/smoke.yml +27 -0
  5. package/.github/workflows/validate-code.yml +51 -0
  6. package/.prettierignore +19 -0
  7. package/.prettierrc +12 -0
  8. package/.release-it.json +66 -0
  9. package/CHANGELOG.md +545 -0
  10. package/CLAUDE.md +55 -0
  11. package/CONTRIBUTING.md +117 -0
  12. package/dist/index.js +221 -62
  13. package/docs/api-references/_meta.json +9 -0
  14. package/docs/api-references/accounts/_meta.json +3 -0
  15. package/docs/api-references/accounts/account/create.mdx +19 -0
  16. package/docs/api-references/accounts/account/export.mdx +19 -0
  17. package/docs/api-references/accounts/account/import.mdx +22 -0
  18. package/docs/api-references/accounts/account/list.mdx +15 -0
  19. package/docs/api-references/accounts/account/lock.mdx +16 -0
  20. package/docs/api-references/accounts/account/remove.mdx +20 -0
  21. package/docs/api-references/accounts/account/send.mdx +24 -0
  22. package/docs/api-references/accounts/account/show.mdx +17 -0
  23. package/docs/api-references/accounts/account/unlock.mdx +17 -0
  24. package/docs/api-references/accounts/account/use.mdx +19 -0
  25. package/docs/api-references/accounts/account.mdx +32 -0
  26. package/docs/api-references/configuration/_meta.json +4 -0
  27. package/docs/api-references/configuration/config/get.mdx +21 -0
  28. package/docs/api-references/configuration/config/reset.mdx +21 -0
  29. package/docs/api-references/configuration/config/set.mdx +21 -0
  30. package/docs/api-references/configuration/config.mdx +25 -0
  31. package/docs/api-references/configuration/network/info.mdx +15 -0
  32. package/docs/api-references/configuration/network/list.mdx +15 -0
  33. package/docs/api-references/configuration/network/set.mdx +21 -0
  34. package/docs/api-references/configuration/network.mdx +25 -0
  35. package/docs/api-references/contracts/_meta.json +7 -0
  36. package/docs/api-references/contracts/call.mdx +21 -0
  37. package/docs/api-references/contracts/code.mdx +20 -0
  38. package/docs/api-references/contracts/deploy.mdx +17 -0
  39. package/docs/api-references/contracts/schema.mdx +20 -0
  40. package/docs/api-references/contracts/write.mdx +21 -0
  41. package/docs/api-references/environment/_meta.json +7 -0
  42. package/docs/api-references/environment/init.mdx +20 -0
  43. package/docs/api-references/environment/new.mdx +21 -0
  44. package/docs/api-references/environment/stop.mdx +15 -0
  45. package/docs/api-references/environment/up.mdx +20 -0
  46. package/docs/api-references/environment/update/ollama.mdx +16 -0
  47. package/docs/api-references/environment/update.mdx +23 -0
  48. package/docs/api-references/index.mdx +35 -0
  49. package/docs/api-references/localnet/_meta.json +3 -0
  50. package/docs/api-references/localnet/localnet/validators/count.mdx +15 -0
  51. package/docs/api-references/localnet/localnet/validators/create-random.mdx +16 -0
  52. package/docs/api-references/localnet/localnet/validators/create.mdx +19 -0
  53. package/docs/api-references/localnet/localnet/validators/delete.mdx +16 -0
  54. package/docs/api-references/localnet/localnet/validators/get.mdx +16 -0
  55. package/docs/api-references/localnet/localnet/validators/update.mdx +23 -0
  56. package/docs/api-references/localnet/localnet/validators.mdx +28 -0
  57. package/docs/api-references/localnet/localnet.mdx +23 -0
  58. package/docs/api-references/staking/_meta.json +3 -0
  59. package/docs/api-references/staking/staking/active-validators.mdx +18 -0
  60. package/docs/api-references/staking/staking/banned-validators.mdx +18 -0
  61. package/docs/api-references/staking/staking/delegation-info.mdx +25 -0
  62. package/docs/api-references/staking/staking/delegator-claim.mdx +26 -0
  63. package/docs/api-references/staking/staking/delegator-exit.mdx +26 -0
  64. package/docs/api-references/staking/staking/delegator-join.mdx +26 -0
  65. package/docs/api-references/staking/staking/epoch-info.mdx +19 -0
  66. package/docs/api-references/staking/staking/prime-all.mdx +20 -0
  67. package/docs/api-references/staking/staking/quarantined-validators.mdx +18 -0
  68. package/docs/api-references/staking/staking/set-identity.mdx +33 -0
  69. package/docs/api-references/staking/staking/set-operator.mdx +26 -0
  70. package/docs/api-references/staking/staking/validator-claim.mdx +24 -0
  71. package/docs/api-references/staking/staking/validator-deposit.mdx +25 -0
  72. package/docs/api-references/staking/staking/validator-exit.mdx +25 -0
  73. package/docs/api-references/staking/staking/validator-history.mdx +29 -0
  74. package/docs/api-references/staking/staking/validator-info.mdx +25 -0
  75. package/docs/api-references/staking/staking/validator-join.mdx +22 -0
  76. package/docs/api-references/staking/staking/validator-prime.mdx +25 -0
  77. package/docs/api-references/staking/staking/validators.mdx +19 -0
  78. package/docs/api-references/staking/staking/wizard.mdx +20 -0
  79. package/docs/api-references/staking/staking.mdx +42 -0
  80. package/docs/api-references/transactions/_meta.json +6 -0
  81. package/docs/api-references/transactions/appeal-bond.mdx +20 -0
  82. package/docs/api-references/transactions/appeal.mdx +21 -0
  83. package/docs/api-references/transactions/receipt.mdx +25 -0
  84. package/docs/api-references/transactions/trace.mdx +21 -0
  85. package/docs/delegator-guide.md +203 -0
  86. package/docs/validator-guide.md +329 -0
  87. package/esbuild.config.dev.js +17 -0
  88. package/esbuild.config.js +22 -0
  89. package/esbuild.config.prod.js +17 -0
  90. package/eslint.config.js +60 -0
  91. package/package.json +2 -11
  92. package/renovate.json +22 -0
  93. package/scripts/generate-cli-docs.mjs +68 -5
  94. package/src/commands/account/create.ts +30 -0
  95. package/src/commands/account/export.ts +106 -0
  96. package/src/commands/account/import.ts +135 -0
  97. package/src/commands/account/index.ts +129 -0
  98. package/src/commands/account/list.ts +34 -0
  99. package/src/commands/account/lock.ts +39 -0
  100. package/src/commands/account/remove.ts +30 -0
  101. package/src/commands/account/send.ts +162 -0
  102. package/src/commands/account/show.ts +74 -0
  103. package/src/commands/account/unlock.ts +56 -0
  104. package/src/commands/account/use.ts +21 -0
  105. package/src/commands/config/getSetReset.ts +51 -0
  106. package/src/commands/config/index.ts +30 -0
  107. package/src/commands/contracts/call.ts +39 -0
  108. package/src/commands/contracts/code.ts +33 -0
  109. package/src/commands/contracts/deploy.ts +161 -0
  110. package/src/commands/contracts/index.ts +150 -0
  111. package/src/commands/contracts/schema.ts +31 -0
  112. package/src/commands/contracts/write.ts +49 -0
  113. package/src/commands/general/index.ts +45 -0
  114. package/src/commands/general/init.ts +180 -0
  115. package/src/commands/general/start.ts +128 -0
  116. package/src/commands/general/stop.ts +26 -0
  117. package/src/commands/localnet/index.ts +100 -0
  118. package/src/commands/localnet/validators.ts +269 -0
  119. package/src/commands/network/index.ts +29 -0
  120. package/src/commands/network/setNetwork.ts +77 -0
  121. package/src/commands/scaffold/index.ts +16 -0
  122. package/src/commands/scaffold/new.ts +34 -0
  123. package/src/commands/staking/StakingAction.ts +279 -0
  124. package/src/commands/staking/delegatorClaim.ts +41 -0
  125. package/src/commands/staking/delegatorExit.ts +56 -0
  126. package/src/commands/staking/delegatorJoin.ts +44 -0
  127. package/src/commands/staking/index.ts +357 -0
  128. package/src/commands/staking/setIdentity.ts +78 -0
  129. package/src/commands/staking/setOperator.ts +46 -0
  130. package/src/commands/staking/stakingInfo.ts +584 -0
  131. package/src/commands/staking/validatorClaim.ts +43 -0
  132. package/src/commands/staking/validatorDeposit.ts +48 -0
  133. package/src/commands/staking/validatorExit.ts +63 -0
  134. package/src/commands/staking/validatorHistory.ts +300 -0
  135. package/src/commands/staking/validatorJoin.ts +47 -0
  136. package/src/commands/staking/validatorPrime.ts +73 -0
  137. package/src/commands/staking/wizard.ts +809 -0
  138. package/src/commands/transactions/appeal.ts +83 -0
  139. package/src/commands/transactions/index.ts +60 -0
  140. package/src/commands/transactions/receipt.ts +90 -0
  141. package/src/commands/transactions/trace.ts +42 -0
  142. package/src/commands/update/index.ts +25 -0
  143. package/src/commands/update/ollama.ts +103 -0
  144. package/src/lib/actions/BaseAction.ts +301 -0
  145. package/src/lib/clients/jsonRpcClient.ts +41 -0
  146. package/src/lib/clients/system.ts +73 -0
  147. package/src/lib/config/ConfigFileManager.ts +194 -0
  148. package/src/lib/config/KeychainManager.ts +89 -0
  149. package/src/lib/config/simulator.ts +68 -0
  150. package/src/lib/config/text.ts +2 -0
  151. package/src/lib/errors/missingRequirement.ts +9 -0
  152. package/src/lib/errors/versionRequired.ts +9 -0
  153. package/src/lib/interfaces/ISimulatorService.ts +39 -0
  154. package/src/lib/services/simulator.ts +386 -0
  155. package/src/types/node-fetch.d.ts +1 -0
  156. package/tests/actions/appeal.test.ts +141 -0
  157. package/tests/actions/call.test.ts +94 -0
  158. package/tests/actions/code.test.ts +87 -0
  159. package/tests/actions/create.test.ts +65 -0
  160. package/tests/actions/deploy.test.ts +420 -0
  161. package/tests/actions/getSetReset.test.ts +88 -0
  162. package/tests/actions/init.test.ts +483 -0
  163. package/tests/actions/lock.test.ts +86 -0
  164. package/tests/actions/new.test.ts +80 -0
  165. package/tests/actions/ollama.test.ts +193 -0
  166. package/tests/actions/receipt.test.ts +261 -0
  167. package/tests/actions/schema.test.ts +94 -0
  168. package/tests/actions/setNetwork.test.ts +161 -0
  169. package/tests/actions/staking.test.ts +280 -0
  170. package/tests/actions/start.test.ts +257 -0
  171. package/tests/actions/stop.test.ts +77 -0
  172. package/tests/actions/unlock.test.ts +139 -0
  173. package/tests/actions/validators.test.ts +750 -0
  174. package/tests/actions/write.test.ts +102 -0
  175. package/tests/commands/account.test.ts +146 -0
  176. package/tests/commands/appeal.test.ts +97 -0
  177. package/tests/commands/call.test.ts +78 -0
  178. package/tests/commands/code.test.ts +69 -0
  179. package/tests/commands/config.test.ts +54 -0
  180. package/tests/commands/deploy.test.ts +83 -0
  181. package/tests/commands/init.test.ts +101 -0
  182. package/tests/commands/localnet.test.ts +131 -0
  183. package/tests/commands/network.test.ts +60 -0
  184. package/tests/commands/new.test.ts +68 -0
  185. package/tests/commands/parseArg.test.ts +156 -0
  186. package/tests/commands/receipt.test.ts +142 -0
  187. package/tests/commands/schema.test.ts +67 -0
  188. package/tests/commands/staking.test.ts +329 -0
  189. package/tests/commands/stop.test.ts +27 -0
  190. package/tests/commands/up.test.ts +105 -0
  191. package/tests/commands/update.test.ts +45 -0
  192. package/tests/commands/write.test.ts +76 -0
  193. package/tests/index.test.ts +56 -0
  194. package/tests/libs/baseAction.test.ts +535 -0
  195. package/tests/libs/configFileManager.test.ts +118 -0
  196. package/tests/libs/jsonRpcClient.test.ts +59 -0
  197. package/tests/libs/keychainManager.test.ts +156 -0
  198. package/tests/libs/platformCommands.test.ts +78 -0
  199. package/tests/libs/system.test.ts +148 -0
  200. package/tests/services/simulator.test.ts +789 -0
  201. package/tests/smoke.test.ts +134 -0
  202. package/tests/utils.ts +13 -0
  203. package/tsconfig.json +120 -0
  204. package/vitest.config.ts +13 -0
  205. package/vitest.smoke.config.ts +17 -0
@@ -0,0 +1,279 @@
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
+ }
@@ -0,0 +1,41 @@
1
+ import {StakingAction, StakingConfig} from "./StakingAction";
2
+ import type {Address} from "genlayer-js/types";
3
+
4
+ export interface DelegatorClaimOptions extends StakingConfig {
5
+ validator: string;
6
+ delegator?: string;
7
+ }
8
+
9
+ export class DelegatorClaimAction extends StakingAction {
10
+ constructor() {
11
+ super();
12
+ }
13
+
14
+ async execute(options: DelegatorClaimOptions): Promise<void> {
15
+ this.startSpinner("Claiming delegator withdrawals...");
16
+
17
+ try {
18
+ const client = await this.getStakingClient(options);
19
+ const delegatorAddress = options.delegator || (await this.getSignerAddress());
20
+
21
+ this.setSpinnerText(`Claiming for delegator ${delegatorAddress} from validator ${options.validator}...`);
22
+
23
+ const result = await client.delegatorClaim({
24
+ validator: options.validator as Address,
25
+ delegator: delegatorAddress as Address,
26
+ });
27
+
28
+ const output = {
29
+ transactionHash: result.transactionHash,
30
+ delegator: delegatorAddress,
31
+ validator: options.validator,
32
+ blockNumber: result.blockNumber.toString(),
33
+ gasUsed: result.gasUsed.toString(),
34
+ };
35
+
36
+ this.succeedSpinner("Claim successful!", output);
37
+ } catch (error: any) {
38
+ this.failSpinner("Failed to claim", error.message || error);
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,56 @@
1
+ import {StakingAction, StakingConfig} from "./StakingAction";
2
+ import type {Address} from "genlayer-js/types";
3
+
4
+ export interface DelegatorExitOptions extends StakingConfig {
5
+ validator: string;
6
+ shares: string;
7
+ }
8
+
9
+ export class DelegatorExitAction extends StakingAction {
10
+ constructor() {
11
+ super();
12
+ }
13
+
14
+ async execute(options: DelegatorExitOptions): Promise<void> {
15
+ this.startSpinner("Initiating delegator exit...");
16
+
17
+ try {
18
+ let shares: bigint;
19
+ try {
20
+ shares = BigInt(options.shares);
21
+ if (shares <= 0n) throw new Error("must be positive");
22
+ } catch {
23
+ this.failSpinner(`Invalid shares value: "${options.shares}". Must be a positive whole number.`);
24
+ return;
25
+ }
26
+
27
+ const client = await this.getStakingClient(options);
28
+
29
+ this.setSpinnerText(`Exiting ${shares} shares from validator ${options.validator}...`);
30
+
31
+ const result = await client.delegatorExit({
32
+ validator: options.validator as Address,
33
+ shares,
34
+ });
35
+
36
+ // Check epoch to determine note
37
+ const epochInfo = await client.getEpochInfo();
38
+ const isEpochZero = epochInfo.currentEpoch === 0n;
39
+
40
+ const output = {
41
+ transactionHash: result.transactionHash,
42
+ validator: options.validator,
43
+ sharesWithdrawn: shares.toString(),
44
+ blockNumber: result.blockNumber.toString(),
45
+ gasUsed: result.gasUsed.toString(),
46
+ note: isEpochZero
47
+ ? "Epoch 0: Withdrawal claimable immediately"
48
+ : "Withdrawal will be claimable after the unbonding period",
49
+ };
50
+
51
+ this.succeedSpinner("Exit initiated successfully!", output);
52
+ } catch (error: any) {
53
+ this.failSpinner("Failed to exit", error.message || error);
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,44 @@
1
+ import {StakingAction, StakingConfig} from "./StakingAction";
2
+ import type {Address} from "genlayer-js/types";
3
+ import chalk from "chalk";
4
+
5
+ export interface DelegatorJoinOptions extends StakingConfig {
6
+ validator: string;
7
+ amount: string;
8
+ }
9
+
10
+ export class DelegatorJoinAction extends StakingAction {
11
+ constructor() {
12
+ super();
13
+ }
14
+
15
+ async execute(options: DelegatorJoinOptions): Promise<void> {
16
+ this.startSpinner("Joining as delegator...");
17
+
18
+ try {
19
+ const client = await this.getStakingClient(options);
20
+ const amount = this.parseAmount(options.amount);
21
+
22
+ this.setSpinnerText(`Delegating ${this.formatAmount(amount)} to validator ${options.validator}...`);
23
+
24
+ const result = await client.delegatorJoin({
25
+ validator: options.validator as Address,
26
+ amount,
27
+ });
28
+
29
+ const output = {
30
+ transactionHash: result.transactionHash,
31
+ validator: result.validator,
32
+ amount: result.amount,
33
+ delegator: result.delegator,
34
+ blockNumber: result.blockNumber.toString(),
35
+ gasUsed: result.gasUsed.toString(),
36
+ };
37
+
38
+ this.succeedSpinner("Successfully joined as delegator!", output);
39
+ console.log(chalk.dim(`\nTo view your delegation: genlayer staking delegation-info --validator ${options.validator}`));
40
+ } catch (error: any) {
41
+ this.failSpinner("Failed to join as delegator", error.message || error);
42
+ }
43
+ }
44
+ }