Repository navigation
Conversation
…y key = bytes32(0) (genlayerlabs#190) The wildcard sentinel previously shared bytes32(0) with GenVM's natural empty-method-name key (deploy, emit_transfer), making deploy-specific Mode-2 allocations impossible. Per cross-team decision, the wildcard moves to the untagged keccak256 of empty bytes (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470), which is provably outside the derived-key space. DEPLOY_CALL_KEY drops the bytes32(1) sentinel (GenVM ask withdrawn) and now equals CALL_KEY_UNNAMED = bytes32(0), matching what GenVM actually emits. Must land together with the consensus CALL_KEY_WILDCARD constant and the node Mode-2 tree decode change in v0.6.
…layerlabs#195) * feat(sdk): developer-NFT read/claim actions Expose the on-chain developer-NFT reward flow: getDeveloperNft, getClaimableRewardsFromFees, getClaimableRewardsFromInflation, claimNft rewards/epochs. NFTMinter ABI + AddressManager-based address resolution. Mirrors existing action patterns; unit tests added. (Codex-generated; build + 90 tests green. Base is fix/callkey-wildcard-sentinel — rebase onto v2-dev before PR.) * fix(nonce): coerce eth_getTransactionCount hex string to number getCurrentNonce returned the RPC's hex quantity string while the declared return type (and callers) expect a number. On the local-account signing path the raw string flows into viem's transaction serializer, which encodes the ASCII characters as the nonce bytes — producing an unmineable transaction and an infinite receipt wait. Affects any local-account consensus call (appeals, top-ups) on network backends.
* feat: add vesting delegator actions * feat(vesting): validator-leg actions (join/deposit/exit/claim, operator transfer, identity, wallet reads) Implements the CON-607 Vesting.sol validator surface (consensus branch con-607-vesting-lock-then-validate): vestingValidatorJoin/Deposit/Exit/ Claim, operator-transfer initiate/complete/cancel, setIdentity, and getValidatorWallets/validatorWalletCount/validatorDeposited/ isValidatorWallet reads. Replaces the #1154 stub in vesting/validator.ts.
…ke) (genlayerlabs#194) * feat: getCurrentEpoch + isValidatorBelowMinStake epoch-zero helpers Convenience reads for epoch-0-aware tooling: getCurrentEpoch() (bootstrap epoch where min stake is not enforced) and isValidatorBelowMinStake() so callers can present a below-min validator as bootstrapping vs faulted while epoch is 0. Additive; existing signatures unchanged. * fix(types): add epoch-zero fields to ValidatorInfo getValidatorInfo returns currentEpoch, validatorMinStake, validatorMinStakeRaw, and belowMin, but the ValidatorInfo interface was never extended to include them, breaking the dts build (TS2353) and failing the drift, test, and smoke checks.
…bs#196) This file is a temporary artifact emitted by `vitest --typecheck` and deleted/regenerated on each run, so committing it produced spurious working-tree changes on every test run. It was accidentally committed in genlayerlabs#145 (34de39f). Remove it from tracking and ignore `tsconfig.vitest-temp*.json` so the tree stays clean.
genlayerlabs#200) B1: executeWrite in staking + vesting now branches on account.type === "local". The local-key path (getTransactionCount -> prepareTransactionRequest -> sign -> sendRawTransaction) is unchanged and stays the regression gate. Address-only / injected-provider accounts route through client.request eth_sendTransaction (wallet manages nonce + signing), mirroring the proven IC provider lane in src/contracts/actions.ts. Shared preflight simulate + gas estimate and the post-mine receipt wait / revert diagnostics are unchanged around the branch. B2: new accountActions.transfer({to, value}) for native GEN transfers, local-key only, mirroring the executeWrite local lane. accountActions now takes publicClient. Unblocks CLI browser-wallet writes routing through the SDK.
…ng) (genlayerlabs#192) The v0.6 genvm-manager renamed the method-call calldata map key from "method" to "" (empty string). The empty key sorts first in canonical calldata map encoding (keys ordered by unicode-codepoint array; the empty array precedes any non-empty key), so the method name becomes a prefix of the encoded binary calldata. makeCalldataObject now writes the method name under ret[""]. The decoder is unchanged: it builds a generic Map from raw key bytes and already reads whatever key is present. No back-compat toggle — there is no calldata versioning mechanism in this repo, so this is a hard cutover. The genvm-manager still auto-remaps "method" -> "" but logs an error each time; this migration stops that error. BREAKING CHANGE: method-call calldata now uses the "" key instead of "method". Encoded bytes for every write/read/view/schema call change. Peers must run the v0.6 genvm-manager (or a node/studio build that expects the "" key).
* fix: support proof-bearing vesting validator joins * fix: require operator proofs for validator joins
… on its 4 companions) (genlayerlabs#208) * Reapply "fix: support proof-bearing validator joins (genlayerlabs#206)" (genlayerlabs#207) This reverts commit 7666f0b. * feat(staking): support the two-step operator rotation CON-715 removed ValidatorWalletBlueprint.setOperator in favour of initiateOperatorTransfer + completeOperatorTransfer. The SDK only spoke the single-call surface, so rotating an operator against a consensus deployment that carries the change fails: the selector no longer exists, so viem reverts with no reason and the Python SDK reports ABIFunctionNotFound. Adds both calls plus cancelOperatorTransfer and the getPendingOperator view, and keeps setOperator for deployments that still expose it. The proof binding is the subtle part. validatorJoin's possession proof is verified by the ValidatorWalletFactory and is bound to it; rotation is verified by the wallet, so the registrar is the wallet's own address (PubKeyUtils.validateWithPossession(pubKey, address(this), owner(), proof)). createOperatorRegistration already takes the registrar as a parameter, so no change was needed there — but a join proof silently fails to verify for a rotation, which is the easy mistake to make. getOperatorTransferContext builds the wallet-bound context and reads owner() from the wallet rather than assuming the caller is the owner, so a mismatch surfaces as a clear local error instead of an onlyOwner revert. A test pins that a join-bound proof does not verify for rotation while a wallet-bound one does. Callers still need updating; this only adds the surface they need: genlayer-e2e's driver interface, genlayer-cli's staking set-operator, and genlayer-py's staking_set_operator all remain single-call. Verified: npx tsc --noEmit, npm test -- --run (123/123, no type errors), npm run build. * fix(staking): resolve the Claim/Commit layout from the chain CON-715 widened both staking structs — Claim gained `offset`, Commit gained `outstanding`/`priced`/`fragmented` and narrowed several members — while keeping the same function names and arguments. Static tuples decode positionally, so reading a post-CON-715 chain with the shape in STAKING_ABI does not fail: `commit.input` picks up `claim.commit`. Pending deposits came back as small indices instead of amounts, which is why the e2e delegator scenarios asserted 0.1 GEN and got "0" or "2". Both layouts are deployed — consensus v0.6-dev has the old one, #1290 the new — so neither shape can simply replace the other. STAKING_COMMIT_VIEWS_CURRENT_ABI adds the post-CON-715 shape for the four struct-returning views, and readCommitView resolves which one the chain speaks, once, then caches it for the client: getStakeInfo loops over every pending entry and must not re-probe per entry. The probe only works in one direction, and the tests pin that: decoding a legacy response with the current shape throws (the response is short), while decoding a current response with the legacy shape succeeds and lies. So the current shape is always attempted first and a decode *failure* identifies a legacy chain. If that asymmetry ever breaks, the probe would quietly start reporting wrong balances again — hence the test asserting the exact misread value rather than merely "not equal". Also drops duplicate ValidatorWalletBlueprint entries: the ABI already carried initiateOperatorTransfer/completeOperatorTransfer/cancelOperatorTransfer/ getPendingOperator, with initiateOperatorTransfer declared as taking an address rather than the pubkey and possession proof it actually takes. Verified: npx tsc --noEmit, npm test -- --run (126/126, no type errors), npm run build. --------- Co-authored-by: kirilaa <kirilantevski@gmail.com>
…bs#212) * fix: read the consensus surfaces the resolution-kernel train exposes Four entrypoints the SDK calls were removed or reshaped by the train. The first one is what fails in E2E today, on the dev-env stack, before any scenario completes: getTransactionData(txId, timestamp) -> not found on ABI That read answered with a projection evaluated at a caller-supplied clock. The train splits the two apart: the stored record is getStoredTransactionData(txId) and the projection lives behind getTransactionLifecycle. Chains upgrade independently, so the transaction read now picks whichever the chain's OWN abi offers rather than assuming -- the dev-env harness builds its chain from the live deployment, so its abi is the train's while a testnet's is not. The stored record renames three fields. The decoder already normalised two of them (txData/txCalldata, numOfInitialValidators/initialRotations); it now also accepts observedAt for currentTimestamp, which it reads unconditionally, so an unrecognised name was a crash rather than a missing field. activeValidators() is gone because committee capacity is 1,543 and an address[] that long overruns the return-size limit. The joined registry is paged instead: read validatorsJoinedCount() first so a registry that grows underneath the walk cannot spin the loop, then getValidatorsJoined 64 at a time -- the size the paged reads are written around, and the one genlayer-node uses for the same walk. activeValidatorsCount() went with it, which took all of getEpochInfo() down with a single read. validatorView lost its registry tree pointers (left, right, parent), so the struct is resynced to the nine fields the train returns; both call sites read it by name, so nothing else moves. validatorsRoot() is removed from the abi as well -- nothing here calls it, and leaving a declaration for a function that no longer exists only invites a revert. The status map is renumbered with them. ReadyToFinalize stopped being a stored status -- readiness is the resolution kernel's verdict now -- and removing it at ordinal 11 shifts the three above it down. Left alone, a ValidatorsTimeout transaction decoded as "READY_TO_FINALIZE": no error, just the wrong answer. The enum member stays, because the node still reports that state; what changed is that no chain value decodes to it, so the name->number map is now partial and says so in its type. The repo's own tests pinned the old numbering and are re-pointed to the train's. * fix: resync validatorViewPrimed and validatorViewPrePrimed The earlier commit resynced validatorView and missed its two siblings, which return the same struct and drifted the same way: the train dropped the registry tree pointers (left, right, parent), so a twelve-field decode runs off the end of a nine-field return. It surfaces as a bounds error rather than a wrong value -- "Position 319 is out of bounds (0 < position < 288)" from validatorViewPrimed -- because the reader walks past the encoded tail. * fix: align SDK consumers with train contracts * fix: route studio chains around the train lifecycle reads The train adaptation made the appeal and finalization actions read getTransactionLifecycle from ConsensusData unconditionally. Studio chains (localnet, studionet) run the studio-embedded consensus, which predates the train: that ConsensusData exposes no getTransactionLifecycle and no estimateLatestAppealCharge, so the read decodes a short tuple and viem raises "Position 63 is out of bounds (0 < position < 32)". This failed the studio suites of e2e run 33112369501, including 051_fee_lifecycle.feature ("submitAppeal records an appeal bond without expanding the primary fee budget"). Guard each affected action on client.chain.isStudio before any train read, mirroring transactionActions.getTransaction, and reinstate the pre-train call shape recovered from the v2-dev base: - appealTransaction encodes submitAppeal(bytes32) against the chain's own ConsensusMain ABI, with the caller's value defaulting to zero. The base resolved the value through FeeManager/RoundsStorage, both of which carry no address on studio, so it already degraded to zero there. - topUpAndSubmitAppeal encodes topUpAndSubmitAppeal(bytes32, FeesDistribution) without a decision id. - finalizeTransaction encodes finalizeTransaction(bytes32). - getAppealCharge and getMinAppealBond report the missing quote surface, which is the error the base already raised on studio. - resolveTransactions and finalizeDecisions are train-only additions with no base equivalent, so they report the gap and point at finalizeTransaction. canAppeal and the rounds-storage reads already returned their base error on studio: their missing-contract guards run before any train read, so they are left alone. finalizeIdlenessTxs keeps its migration error; studio's ConsensusMain ABI never carried that entrypoint, so the base did not support it there either. The train path is unchanged for non-studio chains. * feat(transactions)!: layer consumer and protocol lifecycles Keep the default transaction model on materialized state with a small discriminated lifecycle and stored-state wait helpers. Move projection, resolution source/action, and active decision identity behind the advanced namespace using one normalized schema on both Studio and contract networks.\n\nRemove ReadyToFinalize and duplicate canFinalize exposure. Finalize remains a protocol action.\n\nValidation: npm test -- --run; npm run lint; npm run build; npm run docs; git diff --check. * fix(staking): restore complete public action surface * fix(types): stop merging unrelated transaction results * fix(appeals): bind Studio calls to decisions * fix(appeals): use train ABI on Studio networks * fix(lifecycle): fall back to the Studio status when the RPC is absent The train surface routes Studio chains through the node RPC gen_getTransactionLifecycle: advanced.getTransactionLifecycle reads it directly, and _readLifecycleIdentity reads it for every appeal and finalization. The genlayer-studio backend deployed from studio main does not implement that method, so viem raises MethodNotFoundRpcError and the whole flow dies before it reaches anything the transaction can answer. Keep the node-RPC-first design and degrade only when the endpoint says it does not implement the method (viem's typed error, JSON-RPC -32601, or a message that reports the gap in text). The fallback synthesizes the lifecycle from the Studio consumer surface the SDK already uses, client.getTransaction, which proves the exact stored status and nothing else: the projection repeats the stored status, the resolution is NoOp/Unspecified, and the decision identity stays inactive. When the status cannot be read, the original RPC error is re-raised rather than reported as a lifecycle. _readLifecycleIdentity returns the same conservative identity, so a Studio chain without the RPC reports no decision instead of a fabricated one. A fabricated decision id would be signed into submitAppeal or finalizeTransaction as expectedDecisionId, and every consumer of that identity refuses to act on an inactive decision, which is the honest outcome for a decision the SDK cannot read. This unblocks the Studio flows that never touch a decision. It does not make the four appeal scenarios of 051_fee_lifecycle pass: those need a real active decision id on Studio, which only the backend can supply. * fix(studio): preserve the current consensus surface * fix(fees): fund default consensus rotations in estimates --------- Co-authored-by: Edgars <edgars@genlayerlabs.com> Co-authored-by: kirilaa <kiril@yeager.ai>
* fix(fees): mirror consensus deposit quote * fix(studio): bind decision lifecycle actions Use Studio's lifecycle and appeal-charge RPCs to bind appeal, combined top-up/appeal, and finalization to the active decision. Keep Studio ABI exports aligned with the v0.6 consensus surface and cover quoting and guarded selectors. * fix(fees): encode internal message price caps * fix(studio): surface mined envelope reverts * fix(fees): encode schedule-free topups * fix(transactions): discover message payment events * test(appeals): lock configured contract routing Verify that canAppeal reads the active decision from the separately configured Appeals contract at the lifecycle snapshot. This catches local-chain interface drift before cross-stack E2E. * fix(appeals): admit unfunded rounds safely Route the public appeal action through topUpAndSubmitAppeal, whose consensus-derived schedule extension is valid for both pre-funded and unfunded rounds. Keep the direct submitAppeal selector out of the high-level path so a full bond-plus-funding quote cannot still fail AppealRoundNotPermitted.\n\nCover quoted and caller-provided values on deployed Consensus and Studio, and refresh generated API docs.
Add the dedicated Studio dev chain preset and make prerelease npm publication use a non-latest channel.
Remove the CI-suppression marker from release commits and directly test the real release configuration against GitHub skip directives.
…cer (genlayerlabs#220) * fix(staking): follow the CON-471 ValidatorStake.live -> hasUnclaimedRewards rename genlayer-consensus renames `ValidatorStake.live` to `hasUnclaimedRewards` (the flag marks unclaimed inflation rewards, not node liveness). Update the staking ABI tuple, the `ValidatorView` types and the view mapper, and the fixtures/smoke assertion that read the old key. Depends-On: genlayerlabs/genlayer-consensus#1403 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KVkzRWuHBntyhom3xqHEAG * fix(consumers): align staking and lifecycle reads with the migration producer Reconcile the staking ABI subset against consensus c4749a420, retain both reward-flag states independently of bans, and preserve uint256 claim amounts and execution generation. Add producer-derived fixtures and document pre-release package delivery and remaining integration requirements. * fix(transactions): discover canonical children across deferred delivery --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: kirilaa <kirilantevski@gmail.com>
…layerlabs#223) Read FeeManager receiptWrapperBytes and quote propose-receipt gas with the effective gasPrice. Plain eth_call can expose tx.gasprice=0, which makes the Nitro rollup gas model revert. Avoid the zero-price messageFeeParamsBudgetFloor view and use the configured receipt wrapper plus Consensus #1692 terminal reserve. Recognize chain-derived pricing even when its plain-call quote is zero. Mirror the same floor in Studio when its RPC omits the authoritative value. Validation: 202 Vitest tests and typecheck, production build, changed-file ESLint, and diff whitespace check.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cae5e549f5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }, | ||
| }, | ||
| // The stable Studio explorer does not index this preview deployment. | ||
| blockExplorers: undefined, |
There was a problem hiding this comment.
Omit the explorer field when no explorer exists
When connect("studioDevnet") tries to add the newly exported chain to a wallet, this undefined explorer is converted by src/wallet/connect.ts into blockExplorerUrls: [undefined] (serialized as [null]). Wallets such as MetaMask validate every supplied explorer URL and reject the entire wallet_addEthereumChain request, preventing first-time connections to Studio Devnet. Omit blockExplorerUrls when the chain has no explorer rather than supplying an array with an invalid element.
Useful? React with 👍 / 👎.
|
|
||
| let hash: `0x${string}`; | ||
| if (account.type === "local") { | ||
| const nonce = await publicClient.getTransactionCount({address: account.address as ViemAddress}); |
There was a problem hiding this comment.
Read the pending nonce for vesting writes
When two local-key vesting writes are submitted before the first is mined, this call uses viem's default latest block tag, so both transactions can receive the same nonce and the second is rejected as already known or as an underpriced replacement. The new transfer path already requests blockTag: "pending" for this reason; the shared vesting write path should do the same.
Useful? React with 👍 / 👎.
| const functionName = hasAbiFunction(consensusMainContract.abi, "getAddressManager") | ||
| ? "getAddressManager" | ||
| : hasAbiFunction(consensusMainContract.abi, "addressManager") | ||
| ? "addressManager" | ||
| : undefined; |
There was a problem hiding this comment.
Resolve the AddressManager on Studio presets
On the built-in localnet, studionet, and new studioDevnet presets, consensusMainContract.abi contains neither getAddressManager nor addressManager, so every newly added developer-NFT method fails here with the local “missing AddressManager getter” error before making an RPC request. The staking and vesting paths already call getAddressManager through a minimal dedicated ABI; use the same approach here instead of requiring the static preset ABI to advertise the getter.
Useful? React with 👍 / 👎.
Temporary fork-only verification for upstream PR genlayerlabs#226; source code is identical to its upstream PR head, plus a diagnostic GitHub Actions workflow. Do not merge. Close after collecting CI results.