Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions src/commands/staking/StakingAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ export class StakingAction extends BaseAction {
return {...session, stakingAddress};
}

/**
* Build a staking client bound to a browser-wallet session: an Address-only
* account plus the session's EIP-1193 provider. The SDK's `executeWrite`
* branches on `account.type` — for an Address it routes `eth_sendTransaction`
* through the provider (the bridge signs), so browser writes run the exact
* same `client.<method>(...)` calls as the keystore lane. No keystore /
* keychain / password code path is ever touched. Callers should
* `session.setNextLabel(...)` before each write so the bridge shows a
* human-readable label instead of a generic one.
*/
protected getBrowserStakingClient(
config: StakingConfig,
session: BrowserSession,
): GenLayerClient<GenLayerChain> {
const network = this.getNetwork(config);
if (config.stakingAddress) {
network.stakingContract = {address: config.stakingAddress as Address, abi: abi.STAKING_ABI};
}
return createClient({
chain: network,
endpoint: config.rpc,
account: session.signerAddress,
provider: session.eip1193Provider,
} as Parameters<typeof createClient>[0]);
}

protected async getStakingClient(config: StakingConfig): Promise<GenLayerClient<GenLayerChain>> {
if (!this._stakingClient) {
// Set account override if provided
Expand Down
21 changes: 8 additions & 13 deletions src/commands/staking/delegatorClaim.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface DelegatorClaimOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -57,24 +55,21 @@ export class DelegatorClaimAction extends StakingAction {
this.startSpinner("Confirm the transaction in your browser wallet...");
try {
const delegatorAddress = options.delegator || session.signerAddress;
const {to, data} = buildTx(abi.STAKING_ABI as any, session.stakingAddress, "delegatorClaim", [
delegatorAddress as Address,
options.validator as Address,
]);
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Claim delegator withdrawals`,
session.setNextLabel(`Claim delegator withdrawals`);
const result = await client.delegatorClaim({
validator: options.validator as Address,
delegator: delegatorAddress as Address,
});

this.succeedSpinner("Claim successful!", {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
delegator: delegatorAddress,
validator: options.validator,
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
});
} catch (error: any) {
this.failSpinner("Failed to claim", error.message || error);
Expand Down
24 changes: 9 additions & 15 deletions src/commands/staking/delegatorExit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface DelegatorExitOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -80,29 +78,25 @@ export class DelegatorExitAction extends StakingAction {
return;
}

const {to, data} = buildTx(abi.STAKING_ABI as any, session.stakingAddress, "delegatorExit", [
options.validator as Address,
shares,
]);
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Exit ${shares} shares from validator`,
session.setNextLabel(`Exit ${shares} shares from validator`);
const result = await client.delegatorExit({
validator: options.validator as Address,
shares,
});

// Check epoch to determine note
const readClient = await this.getReadOnlyStakingClient(options);
const epochInfo = await readClient.getEpochInfo();
const epochInfo = await client.getEpochInfo();
const isEpochZero = epochInfo.currentEpoch === 0n;

this.succeedSpinner("Exit initiated successfully!", {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
validator: options.validator,
sharesWithdrawn: shares.toString(),
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
note: isEpochZero
? "Epoch 0: Withdrawal claimable immediately"
: "Withdrawal will be claimable after the unbonding period",
Expand Down
27 changes: 11 additions & 16 deletions src/commands/staking/delegatorJoin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import chalk from "chalk";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface DelegatorJoinOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -60,25 +58,22 @@ export class DelegatorJoinAction extends StakingAction {
this.startSpinner("Confirm the transaction in your browser wallet...");
try {
const amount = this.parseAmount(options.amount);
const {to, data} = buildTx(abi.STAKING_ABI as any, session.stakingAddress, "delegatorJoin", [
options.validator as Address,
]);
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
value: amount,
label: `Delegate ${this.formatAmount(amount)} to validator`,
session.setNextLabel(`Delegate ${this.formatAmount(amount)} to validator`);
const result = await client.delegatorJoin({
validator: options.validator as Address,
amount,
});

this.succeedSpinner("Successfully joined as delegator!", {
transactionHash: receipt.transactionHash,
validator: options.validator,
amount: this.formatAmount(amount),
delegator: session.signerAddress,
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
transactionHash: result.transactionHash,
validator: result.validator,
amount: result.amount,
delegator: result.delegator,
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
});
console.log(chalk.dim(`\nTo view your delegation: genlayer staking delegation-info --validator ${options.validator}`));
} catch (error: any) {
Expand Down
26 changes: 14 additions & 12 deletions src/commands/staking/setIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type {
SetIdentityOptions as SdkSetIdentityOptions,
StakingTransactionResult,
} from "genlayer-js/types";
import {buildSetIdentityTx} from "../../lib/wallet/txBuilders";

export interface SetIdentityOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -99,7 +98,17 @@ export class SetIdentityAction extends StakingAction {
this.startSpinner("Confirm the transaction in your browser wallet...");
try {
const validatorWallet = options.validator as Address;
const {to, data} = buildSetIdentityTx(validatorWallet, {
// `setIdentity` exists at runtime but is missing from the installed
// genlayer-js StakingActions .d.ts — cast to bridge that type gap. The
// SDK owns the extraCid encoding (hex passthrough vs UTF-8 -> hex).
const client = this.getBrowserStakingClient(options, session) as GenLayerClient<GenLayerChain> & {
setIdentity(o: SdkSetIdentityOptions): Promise<StakingTransactionResult>;
};

this.log(` From (browser wallet): ${session.signerAddress}`);
session.setNextLabel(`Set identity (${options.moniker})`);
const result = await client.setIdentity({
validator: validatorWallet,
moniker: options.moniker,
logoUri: options.logoUri,
website: options.website,
Expand All @@ -111,19 +120,12 @@ export class SetIdentityAction extends StakingAction {
extraCid: options.extraCid,
});

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Set identity (${options.moniker})`,
});

const output: Record<string, any> = {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
validator: validatorWallet,
moniker: options.moniker,
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
};

// Add optional fields that were set
Expand Down
24 changes: 12 additions & 12 deletions src/commands/staking/setOperator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import type {
SetOperatorOptions as SdkSetOperatorOptions,
StakingTransactionResult,
} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface SetOperatorOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -73,23 +71,25 @@ export class SetOperatorAction extends StakingAction {
this.startSpinner("Confirm the transaction in your browser wallet...");
try {
const validatorWallet = options.validator as Address;
const {to, data} = buildTx(abi.VALIDATOR_WALLET_ABI as any, validatorWallet, "setOperator", [
options.operator as Address,
]);
// `setOperator` exists at runtime but is missing from the installed
// genlayer-js StakingActions .d.ts — cast to bridge that type gap.
const client = this.getBrowserStakingClient(options, session) as GenLayerClient<GenLayerChain> & {
setOperator(o: SdkSetOperatorOptions): Promise<StakingTransactionResult>;
};

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Set operator to ${options.operator}`,
session.setNextLabel(`Set operator to ${options.operator}`);
const result = await client.setOperator({
validator: validatorWallet,
operator: options.operator as Address,
});

this.succeedSpinner("Operator updated!", {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
validator: validatorWallet,
newOperator: options.operator,
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
});
} catch (error: any) {
this.failSpinner("Failed to set operator", error.message || error);
Expand Down
29 changes: 15 additions & 14 deletions src/commands/staking/validatorClaim.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface ValidatorClaimOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -62,21 +60,24 @@ export class ValidatorClaimAction extends StakingAction {
this.startSpinner("Confirm the transaction in your browser wallet...");
try {
const validatorWallet = options.validator as Address;
const {to, data} = buildTx(abi.VALIDATOR_WALLET_ABI as any, validatorWallet, "validatorClaim");
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Claim validator withdrawals`,
});

this.succeedSpinner("Claim successful!", {
transactionHash: receipt.transactionHash,
session.setNextLabel(`Claim validator withdrawals`);
const result = await client.validatorClaim({validator: validatorWallet});

const output: Record<string, any> = {
transactionHash: result.transactionHash,
validator: validatorWallet,
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
});
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
};

if (result.claimedAmount !== undefined) {
output.claimedAmount = this.formatAmount(result.claimedAmount);
}

this.succeedSpinner("Claim successful!", output);
} catch (error: any) {
this.failSpinner("Failed to claim", error.message || error);
} finally {
Expand Down
19 changes: 8 additions & 11 deletions src/commands/staking/validatorDeposit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface ValidatorDepositOptions extends StakingConfig {
amount: string;
Expand Down Expand Up @@ -67,22 +65,21 @@ export class ValidatorDepositAction extends StakingAction {
try {
const amount = this.parseAmount(options.amount);
const validatorWallet = options.validator as Address;
const {to, data} = buildTx(abi.VALIDATOR_WALLET_ABI as any, validatorWallet, "validatorDeposit");
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
value: amount,
label: `Deposit ${this.formatAmount(amount)} to validator`,
session.setNextLabel(`Deposit ${this.formatAmount(amount)} to validator`);
const result = await client.validatorDeposit({
validator: validatorWallet,
amount,
});

this.succeedSpinner("Deposit successful!", {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
validator: validatorWallet,
amount: this.formatAmount(amount),
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
});
} catch (error: any) {
this.failSpinner("Failed to make deposit", error.message || error);
Expand Down
21 changes: 9 additions & 12 deletions src/commands/staking/validatorExit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {StakingAction, StakingConfig} from "./StakingAction";
import type {Address} from "genlayer-js/types";
import {abi} from "genlayer-js";
import {buildTx} from "../../lib/wallet/txBuilders";

export interface ValidatorExitOptions extends StakingConfig {
validator: string;
Expand Down Expand Up @@ -90,26 +88,25 @@ export class ValidatorExitAction extends StakingAction {
}

const validatorWallet = options.validator as Address;
const {to, data} = buildTx(abi.VALIDATOR_WALLET_ABI as any, validatorWallet, "validatorExit", [shares]);
const client = this.getBrowserStakingClient(options, session);

this.log(` From (browser wallet): ${session.signerAddress}`);
const receipt = await session.sendTransaction({
to,
data,
label: `Exit validator (${shares} shares)`,
session.setNextLabel(`Exit validator (${shares} shares)`);
const result = await client.validatorExit({
validator: validatorWallet,
shares,
});

// Check epoch to determine note
const readClient = await this.getReadOnlyStakingClient(options);
const epochInfo = await readClient.getEpochInfo();
const epochInfo = await client.getEpochInfo();
const isEpochZero = epochInfo.currentEpoch === 0n;

this.succeedSpinner("Exit initiated successfully!", {
transactionHash: receipt.transactionHash,
transactionHash: result.transactionHash,
validator: validatorWallet,
sharesWithdrawn: shares.toString(),
blockNumber: receipt.blockNumber.toString(),
gasUsed: receipt.gasUsed.toString(),
blockNumber: result.blockNumber.toString(),
gasUsed: result.gasUsed.toString(),
note: isEpochZero
? "Epoch 0: Withdrawal claimable immediately"
: "Withdrawal will be claimable after the unbonding period",
Expand Down
Loading
Loading