feat(staking): add StakingActions to GenLayerClient#75
Conversation
Mirrors genlayer-js StakingActions so Python consumers don't have to
drop to raw web3.py to stake, delegate, rotate operators, etc. Bundles
slimmed IGenLayerStaking and ValidatorWallet ABIs as JSON resources.
Writes are routed according to on-chain sender checks:
- validatorJoin/Claim/Prime and all delegator methods go to Staking
with the caller EOA as msg.sender.
- validatorDeposit/Exit are routed through the ValidatorWallet's own
forwarders because Staking rejects those two with a wallet-only
sender assertion. Same constraint is being fixed in genlayer-js.
Reads: epoch, active_validators, active_validators_count, is_validator,
get_validator_info, get_stake_info (stakeOf), banned_validators,
validator_min_stake, delegator_min_stake.
Writes: validator_join (payable, operator optional), validator_deposit,
validator_exit, validator_claim, validator_prime, set_operator,
set_identity, delegator_join, delegator_exit, delegator_claim.
GenLayerChain gains an optional staking_contract (SimpleContractInfo);
all existing presets pass None because staking is only configured when
a caller wires it in. Add the address/ABI manually or via a future
chain preset once the staking contract is published per network.
Unit tests assert that each write encodes the right selector and
targets the right contract — critical for the wallet-vs-staking
routing fix. Lifecycle coverage lives in the ci-core-e2e-runner
tooling suite (needs a live node).
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 11 minutes and 48 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (17)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The smoke tests were constructing a stock Web3.HTTPProvider directly. web3.py's HTTPProvider starts its request counter at 0, so every fresh Web3() sends id=0 on its first RPC call. The GenLayer RPC servers reject id=0 with "Invalid Request: Key: 'Request.ID' Error:Field validation for 'ID' failed on the 'required' tag" (go-playground validator's `required` treats int zero as unset), so every fresh HTTPProvider's first call fails. GenLayerProvider (the SDK's own provider) ids requests by int(time.time() * 1000), which is always nonzero, and is the path real consumers already use. Switch the smoke tests to construct via create_client() so we're testing the SDK path, not a bypass. test_rpc_connects no longer calls Web3.is_connected — GenLayerProvider deliberately doesn't implement BaseProvider.is_connected, and any successful RPC call is a stronger liveness signal anyway (chain_id matching 4221 confirms we're reaching the right network too).
Summary
Adds a first-class staking module to the Python SDK so consumers don't have to fall back to raw web3.py. Mirrors the genlayer-js `StakingActions` module one-for-one.
New module: `genlayer_py.staking`
Client surface (on `GenLayerClient`)
Reads: `staking_epoch`, `active_validators`, `active_validators_count`, `is_validator`, `get_validator_info`, `get_stake_info` (→ `stakeOf`), `banned_validators`, `validator_min_stake`, `delegator_min_stake`.
Writes: `validator_join` (payable, operator optional), `validator_deposit`, `validator_exit`, `validator_claim`, `validator_prime`, `set_operator`, `set_identity`, `delegator_join`, `delegator_exit`, `delegator_claim`.
The key routing fix
`validatorDeposit()` and `validatorExit(uint256)` on the `Staking` contract assert `msg.sender == ValidatorWallet`. Calling them from the operator EOA reverts. This SDK routes both through the wallet's own forwarders (same shape as `setOperator`/`setIdentity`), so Staking sees the wallet as sender. The identical fix is going out in genlayer-js#155.
Chain config
`GenLayerChain` gains `staking_contract: Optional[SimpleContractInfo]`. All four existing presets pass `None` — this PR doesn't hard-code staking contract addresses per network. Consumers wire it up at construction time, or we land per-chain addresses in a follow-up once the staking router is published:
```python
from genlayer_py.chains import testnet_bradbury
testnet_bradbury.staking_contract = {
"address": "0x...",
"abi": STAKING_ABI,
}
```
Test plan
Non-goals