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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,12 @@ const isValidator = await client.isValidator("0x...");
// Get validator info
const validatorInfo = await client.getValidatorInfo("0x...");

// Join as validator (requires account with funds)
const result = await client.validatorJoin({ amount: "42000gen" });
// Join as validator (requires an owner account with funds and the operator key)
const registration = await createOperatorRegistration({
privateKey: operatorPrivateKey,
...(await client.getValidatorRegistrationContext()),
});
const result = await client.validatorJoin({ amount: "42000gen", registration });

// Join as delegator
const delegateResult = await client.delegatorJoin({
Expand Down
8 changes: 6 additions & 2 deletions docs/api-references/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,12 @@ const isValidator = await client.isValidator("0x...");
// Get validator info
const validatorInfo = await client.getValidatorInfo("0x...");

// Join as validator (requires account with funds)
const result = await client.validatorJoin({ amount: "42000gen" });
// Join as validator (requires an owner account with funds and the operator key)
const registration = await createOperatorRegistration({
privateKey: operatorPrivateKey,
...(await client.getValidatorRegistrationContext()),
});
const result = await client.validatorJoin({ amount: "42000gen", registration });

// Join as delegator
const delegateResult = await client.delegatorJoin({
Expand Down
2 changes: 1 addition & 1 deletion docs/api-references/staking.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Joins as a validator with the specified stake amount.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| amount | `bigint \| string` | yes | |
| operator | `Address` | no | |
| registration | `OperatorRegistrationProof` | yes | |

**Returns:** `ValidatorJoinResult`

Expand Down
13 changes: 8 additions & 5 deletions docs/api-references/types.Interface.ValidatorJoinOptions.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
# Interface: ValidatorJoinOptions

Defined in: [types/staking.ts:152](https://github.com/genlayerlabs/genlayer-js/blob/eaba6adec6803bdd0b4968e3f0763cf22107acd1/src/types/staking.ts#L152)
Defined in: `src/types/staking.ts`

## Properties

### amount

> **amount**: `string` \| `bigint`

Defined in: [types/staking.ts:153](https://github.com/genlayerlabs/genlayer-js/blob/eaba6adec6803bdd0b4968e3f0763cf22107acd1/src/types/staking.ts#L153)
Defined in: `src/types/staking.ts`

***

### operator?
### registration

> `optional` **operator?**: `` `0x${string}` ``
> **registration**: `OperatorRegistrationProof`

Defined in: [types/staking.ts:154](https://github.com/genlayerlabs/genlayer-js/blob/eaba6adec6803bdd0b4968e3f0763cf22107acd1/src/types/staking.ts#L154)
Proof-of-possession package bound to this chain, the validator wallet factory,
and the joining owner address.

Defined in: `src/types/staking.ts`
171 changes: 132 additions & 39 deletions src/abi/staking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,76 +55,83 @@ export const VALIDATOR_WALLET_ABI = [
inputs: [{name: "_operator", type: "address"}],
outputs: [],
},
// Two-step operator rotation (CON-715). setOperator above is the single-call
// predecessor and is absent from newer consensus deployments, so callers pick
// whichever the deployed wallet exposes. Unlike validatorJoin, the possession
// proof here is verified by the wallet itself, so its registrar is the wallet
// address rather than the ValidatorWalletFactory.
{
name: "setIdentity",
name: "initiateOperatorTransfer",
type: "function",
stateMutability: "nonpayable",
inputs: [
{name: "moniker", type: "string"},
{name: "logoUri", type: "string"},
{name: "website", type: "string"},
{name: "description", type: "string"},
{name: "email", type: "string"},
{name: "twitter", type: "string"},
{name: "telegram", type: "string"},
{name: "github", type: "string"},
{name: "extraCid", type: "bytes"},
{name: "_newOperatorPubKey", type: "uint256[2]"},
{name: "_possessionProof", type: "bytes"},
],
outputs: [],
},
// Staking functions (forwarded to staking contract)
{
name: "validatorDeposit",
name: "completeOperatorTransfer",
type: "function",
stateMutability: "payable",
stateMutability: "nonpayable",
inputs: [],
outputs: [],
},
{
name: "validatorExit",
name: "cancelOperatorTransfer",
type: "function",
stateMutability: "nonpayable",
inputs: [{name: "_shares", type: "uint256"}],
inputs: [],
outputs: [],
},
{
name: "validatorClaim",
name: "getPendingOperator",
type: "function",
stateMutability: "nonpayable",
stateMutability: "view",
inputs: [],
outputs: [],
outputs: [
{name: "", type: "address"},
{name: "", type: "uint256"},
],
},
// Two-step operator transfer
{
name: "initiateOperatorTransfer",
name: "setIdentity",
type: "function",
stateMutability: "nonpayable",
inputs: [{name: "_newOperator", type: "address"}],
inputs: [
{name: "moniker", type: "string"},
{name: "logoUri", type: "string"},
{name: "website", type: "string"},
{name: "description", type: "string"},
{name: "email", type: "string"},
{name: "twitter", type: "string"},
{name: "telegram", type: "string"},
{name: "github", type: "string"},
{name: "extraCid", type: "bytes"},
],
outputs: [],
},
// Staking functions (forwarded to staking contract)
{
name: "completeOperatorTransfer",
name: "validatorDeposit",
type: "function",
stateMutability: "nonpayable",
stateMutability: "payable",
inputs: [],
outputs: [],
},
{
name: "cancelOperatorTransfer",
name: "validatorExit",
type: "function",
stateMutability: "nonpayable",
inputs: [],
inputs: [{name: "_shares", type: "uint256"}],
outputs: [],
},
{
name: "getPendingOperator",
name: "validatorClaim",
type: "function",
stateMutability: "view",
stateMutability: "nonpayable",
inputs: [],
outputs: [
{name: "", type: "address"},
{name: "", type: "uint256"},
],
outputs: [],
},
{
name: "getOperator",
Expand Down Expand Up @@ -1249,14 +1256,10 @@ export const STAKING_ABI = [
name: "validatorJoin",
type: "function",
stateMutability: "payable",
inputs: [{name: "_operator", type: "address"}],
outputs: [{name: "", type: "address"}],
},
{
name: "validatorJoin",
type: "function",
stateMutability: "payable",
inputs: [],
inputs: [
{name: "_operatorPubKey", type: "uint256[2]"},
{name: "_possessionProof", type: "bytes"},
],
outputs: [{name: "", type: "address"}],
},
{
Expand Down Expand Up @@ -1513,3 +1516,93 @@ export const SLASH_ABI = [
],
},
] as const;

/**
* The staking Claim/Commit views as consensus exposes them after CON-715.
*
* That change widened both structs — Claim gained `offset`, Commit gained
* `outstanding`/`priced`/`fragmented` and narrowed several members — while
* keeping the same function names and argument lists. Static tuples decode
* positionally, so reading a post-CON-715 chain with the older shape in
* STAKING_ABI silently returns the wrong words rather than failing: `commit.input`
* picks up `claim.commit`, which is why pending deposits read back as small
* indices instead of amounts.
*
* Both shapes are still in the wild, so neither can simply replace the other.
* stakingActions probes once per client and then reads with whichever matches.
* Decoding the OLD layout with this one throws (the response is too short),
* which is what makes the probe possible; the reverse direction is the silent
* one, so the current shape must always be tried first.
*/
const CURRENT_CLAIM_COMPONENTS = [
{name: "quantity", type: "uint96"},
{name: "offset", type: "uint96"},
{name: "commit", type: "uint256"},
] as const;

const CURRENT_COMMIT_COMPONENTS = [
{name: "input", type: "uint256"},
{name: "output", type: "uint256"},
{name: "outstanding", type: "uint120"},
{name: "epoch", type: "uint64"},
{name: "linkToNextCommit", type: "uint56"},
{name: "priced", type: "bool"},
{name: "fragmented", type: "bool"},
] as const;

export const STAKING_COMMIT_VIEWS_CURRENT_ABI = [
{
name: "delegatorDeposit",
type: "function",
stateMutability: "view",
inputs: [
{name: "_delegator", type: "address"},
{name: "_validator", type: "address"},
{name: "_index", type: "uint256"},
],
outputs: [
{name: "claim_", type: "tuple", components: CURRENT_CLAIM_COMPONENTS},
{name: "commit_", type: "tuple", components: CURRENT_COMMIT_COMPONENTS},
],
},
{
name: "delegatorWithdrawal",
type: "function",
stateMutability: "view",
inputs: [
{name: "_delegator", type: "address"},
{name: "_validator", type: "address"},
{name: "_index", type: "uint256"},
],
outputs: [
{name: "claim_", type: "tuple", components: CURRENT_CLAIM_COMPONENTS},
{name: "commit_", type: "tuple", components: CURRENT_COMMIT_COMPONENTS},
],
},
{
name: "validatorDeposit",
type: "function",
stateMutability: "view",
inputs: [
{name: "_validator", type: "address"},
{name: "_index", type: "uint256"},
],
outputs: [
{name: "epoch_", type: "uint256"},
{name: "commit_", type: "tuple", components: CURRENT_COMMIT_COMPONENTS},
],
},
{
name: "validatorWithdrawal",
type: "function",
stateMutability: "view",
inputs: [
{name: "_validator", type: "address"},
{name: "_index", type: "uint256"},
],
outputs: [
{name: "epoch_", type: "uint256"},
{name: "commit_", type: "tuple", components: CURRENT_COMMIT_COMPONENTS},
],
},
] as const;
12 changes: 11 additions & 1 deletion src/abi/vesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,17 @@ export const VESTING_ABI = [
{name: "vestingDelegatorJoin", type: "function", stateMutability: "nonpayable", inputs: [{name: "validator", type: "address"}, {name: "amount", type: "uint256"}], outputs: []},
{name: "vestingDelegatorExit", type: "function", stateMutability: "nonpayable", inputs: [{name: "validator", type: "address"}, {name: "shares", type: "uint256"}], outputs: []},
{name: "vestingDelegatorClaim", type: "function", stateMutability: "nonpayable", inputs: [{name: "validator", type: "address"}], outputs: []},
{name: "vestingValidatorJoin", type: "function", stateMutability: "nonpayable", inputs: [{name: "operator", type: "address"}, {name: "amount", type: "uint256"}], outputs: []},
{
name: "vestingValidatorJoin",
type: "function",
stateMutability: "nonpayable",
inputs: [
{name: "operatorPubKey", type: "uint256[2]"},
{name: "possessionProof", type: "bytes"},
{name: "amount", type: "uint256"},
],
outputs: [],
},
{name: "vestingValidatorDeposit", type: "function", stateMutability: "nonpayable", inputs: [{name: "wallet", type: "address"}, {name: "amount", type: "uint256"}], outputs: []},
{name: "vestingValidatorExit", type: "function", stateMutability: "nonpayable", inputs: [{name: "wallet", type: "address"}, {name: "shares", type: "uint256"}], outputs: []},
{name: "vestingValidatorClaim", type: "function", stateMutability: "nonpayable", inputs: [{name: "wallet", type: "address"}], outputs: []},
Expand Down
15 changes: 14 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,18 @@ export * as abi from "./abi";
export * from "./transactions/fees";
export {isSuccessful} from "./transactions/actions";
export {parseStakingAmount, formatStakingAmount} from "./staking";
export {vestingActions} from "./vesting";
export {
OPERATOR_REGISTRATION_DOMAIN,
createOperatorRegistration,
operatorAddressFromPublicKey,
operatorPossessionMessage,
verifyOperatorRegistration,
vestingActions,
} from "./vesting";
export type {
CreateOperatorRegistrationOptions,
OperatorPublicKey,
OperatorRegistrationContext,
OperatorRegistrationProof,
} from "./vesting";
export {buildGenVmPositionalArgs} from "./contracts/schema";
Loading
Loading