cluster-tool: drive the folded liqsol_core OPP outpost + real yield flush - #25
cluster-tool: drive the folded liqsol_core OPP outpost + real yield flush#25valthon wants to merge 4 commits into
Conversation
e84708b to
8701bc7
Compare
0038098 to
328dee2
Compare
0059f7e to
3d821e0
Compare
Teach the OPP harness to deploy and drive the folded liqsol_core Solana outpost — the integrated outpost is the harness's only Solana OPP mode. - Upgradeable deploy: SolanaValidatorProcess gains an optional upgradeAuthority; when set the program loads via --upgradeable-program so a ProgramData account exists. SolanaValidatorProcessSteps materializes a per-cluster deployer keypair as that authority (which is also the global_config.admin) before launch. - global_config gating: SolanaOutpostBootstrapper runs initialize_global_config once, then passes admin + global_config (and adminAta on SPL reserve creation) on every OPP admin instruction. OppSolProgram holds the supporting constants: seeds, the BPF upgradeable-loader id, the deployer-keypair path, and the warp args. - ClusterConfig.solanaEpochWarp: a new per-cluster option (resolved through ClusterBuildOptions -> ClusterConfigProvider, exposed as a CLI flag, default off). When set the validator launches warped past Solana epoch 3 so a flush_staking_yield flow can run; off by default because the warp trips the depot's cross-chain deposit nonce window. Unit tests cover the config round-trip, the CLI flag, the --upgradeable-program argv branch, solanaWarpArgs, resolveUpgradeAuthority (creation + idempotency), and OppSolProgram (path helper + warp math).
Drive liqsol_core's genuine staking-yield pipeline instead of injecting a synthetic attestation. SolanaYieldEmitterTool seeds a staker's on-chain yield state via the dev-only dev_seed_staker_yield, then cranks flush_staking_yield so the program itself packs the StakingReward into the outbound buffer — retiring the bespoke add_attestation hand-injection and its hand-rolled Borsh encoding. Because the program derives its own reward ref, the verify matches the depot's unmapped row by the staker's native SOL address (not a fixed external_epoch_ref) and asserts the credited WIRE amount equals the emitted reward. The now-dead SlugName / chain-code / epoch-ref constants are removed. Requires the --features development liqsol_core build (dev_seed_staker_yield is compiled only under that feature), wired into the e2e gate by wire-solana's BUILD.bazel.
3d821e0 to
5453fc4
Compare
…sol-integrated support Dissolve OppSolProgram into canonical homes: the epoch warp becomes a first-class SolanaValidatorProcess option (EpochWarpSlotsPerEpoch / EpochWarpSlot constants; buildArgs emits the pair), the deployer-keypair identity consolidates on SolanaFundingTool (deployerKeypairFile + createDeployerKeypair single owner), the liqsol yield-pipeline PDA seeds join SolanaOutpostBootstrapper.PdaSeed, and the BPF upgradeable-loader id lives on the bootstrapper namespace as a typed PublicKey. Split the SOL-side STAKING_REWARD emission into two Report-validated Steps — planSolanaSeedYield (one dev_seed_staker_yield tx) then planSolanaFlushYield (one flush_staking_yield tx) — via single-tx tool helpers devSeedStakerYield / flushStakingYield; drop the dead wireAccount/shareBps inputs from the SOL path. Correct the epoch-gate attribution (the Clock.epoch >= 3 gate is dev_seed_staker_yield's MIN_SEED_EPOCH, not the flush) and replace the incorrect authex-nonce rationale: the createlink nonce is harness Date.now() validated against the depot's own chain time, so the Solana warp cannot trip it — the warp stays opt-in because it puts the Solana clock ~80 minutes ahead of real time, a non-production condition no other flow needs. Document --solana-epoch-warp in both README create-option tables and the CLAUDE.md CLI sentence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K4FBvbwEeTj7ByeJzjehbQ
|
Checked out the full The solana warp has to stay a setup config because the stock solana-test-validator (Agave) only supports genesis-time cli arguments for time warps. There is no equivalent to anvil's |
…ereum,Solana}Schema ClusterConfig gains dedicated per-chain child schemas — ClusterConfigEthereumSchema (empty today) and ClusterConfigSolanaSchema — as direct, schema-defaulted children, and the epoch-warp opt-in moves from the top-level solanaEpochWarp boolean to solana.epochWarp, with ClusterBuildOptions.solana (SolanaOptions) carrying it through the option chain (the --solana-epoch-warp flag is unchanged via the nested shape leaf). flow-yield-distribution opts in via defaults.solana.epochWarp. Also renames SolanaOutpostBootstrapper.oppAdminAccounts -> getAdminAccounts and OppAdminAccounts -> AdminAccounts (the opp prefix was redundant inside the OPP outpost bootstrapper; accessor verb per naming standards). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jglanz
left a comment
There was a problem hiding this comment.
David, I had claude take a run with full context, style, lint and rules. Comments are applied, your arguments were retained but renamed.
FYI - ALL FLOWS ARE INCAPABLE OF RUNNING AGAINST THE
#nextBRANCH
THIS ISSUE IS BLOCKING BOTH LOCAL ANDe2e-testsWORKFLOW
Both test environments must work for an approval.
Specifically the same system that will run the production build, will also run the flow build, so instructions stating --features development are not acceptable.
| // Per-cluster opt-in (`ClusterConfig.solana.epochWarp`, set only by | ||
| // `flow-yield-distribution`'s scenario `defaults`) — see the config | ||
| // field's doc for why every other flow keeps the real-time clock. | ||
| epochWarp: ctx.config.solana.epochWarp |
There was a problem hiding this comment.
BLOCKER: wire-cluster-tool run relaunches through this step (ClusterManager.launch → runStart), re-passing --warp-slot 12300 against a ledger already at/past it — agave exits 1 with warp slot (12300) cannot be less than the working bank slot (12300) (verified on 4.0.3), so a warped cluster can never be restarted. Gate the warp arg pair on the ledger dir not existing yet, matching --slots-per-epoch's genesis-only semantics.
| if (this.config.clusterDataPath != null) { | ||
| mkdirs(this.config.clusterDataPath) | ||
| const persistedFile = Path.join(this.config.clusterDataPath, "sol-deployer-keypair.json") | ||
| const persistedFile = SolanaFundingTool.deployerKeypairFile(this.config.clusterDataPath) |
There was a problem hiding this comment.
Violation (duplication + invariant): with planStart now materializing the deployer via SolanaFundingTool.createDeployerKeypair, this duplicate persist re-implements it, and the generate-fallback above can mint a different identity than the launched upgrade authority — silently breaking the admin == upgrade authority invariant ensureGlobalConfig depends on. Delegate to createDeployerKeypair (or assert the file exists) and drop the fallback.
| } | ||
| } | ||
| return StakingRewardMsg.toBinary(reward) | ||
| export async function devSeedStakerYield( |
There was a problem hiding this comment.
Violation (tools-return-orchestration-units + mandatory tests): the rewritten tool exports two bare side-effecting write functions — a harness tool returns Step factories (plan*/run* inside a SolanaYieldEmitterTool namespace matching the filename), with the flow composing them; and the rewrite ships ZERO unit tests for either function ("unit tests are mandatory for every created or modified symbol — no exceptions"). Either promote these to tool-level plan*/run* factories with tests, or fold the bodies into the flow's existing named runners.
| a non-production condition no other flow needs, so no other flow enables it. | ||
|
|
||
| Requires the `--features development` `liqsol_core` build (wired into the e2e | ||
| gate by wire-solana's `BUILD.bazel`), since a plain `anchor build` omits |
There was a problem hiding this comment.
the same system that will run the production build, will also run the flow build, so instructions stating --features development are not acceptable.
Merge gate — and it blocks EVERY flow, not just this one: a 7-flow suite run against wire-solana next failed uniformly at deploy-solana: Account \authorityAta` not provided— this branch'sSolanaOutpostBootstrappertargets thenext-integ interface (admin/globalConfig/adminAta, initialize_global_config), and the SOL outpost deploy is in every flow's bootstrap. nextalso lacksdev_seed_staker_yield+ thedevelopment-feature BUILD.bazel wiring **(THIS IS NOT ALOUD)**. Nothing here can go green until wire-solana#385 (next-integ) lands on next`; sequence the merges accordingly.
Summary
Teaches the OPP harness to drive the folded
liqsol_coreintegrated outpost — deployed upgradeable, every admin op gated by aglobal_configPDA — and reworksflow-yield-distributionto exercise the program's real staking-yield path. The integrated outpost is the harness's only Solana OPP mode; the epoch warp the yield flow needs is a per-cluster config option a flow opts into, not a shared env var, so the e2e gate's "no per-flow env" contract holds with zero workflow plumbing.Changes (2 commits)
1.
cluster-tool: drive folded liqsol_core OPP outpost— the harness capability:SolanaValidatorProcessgains an optionalupgradeAuthority; when set, the program loads via--upgradeable-program(so aProgramDataaccount exists).SolanaValidatorProcessStepsdeploysliqsol_corewith the per-cluster SOL deployer as that authority — which is also theglobal_config.admin.global_configgating.SolanaOutpostBootstrapperrunsinitialize_global_configonce, then passesadmin+global_config(andadminAtaon SPL reserve creation) on every OPP admin instruction.OppSolProgramholds the supporting constants (global_config seed, BPF upgradeable-loader id, per-cluster deployer keypair, epoch-warp validator args).ClusterConfig.solanaEpochWarp— a new per-cluster option (resolved throughClusterBuildOptions→ClusterConfigProvider, exposed as a CLI flag, default off). When set, the validator launches warped past Solana epoch 3. Off by default: the warp advances the Solana clock past the depot'ssysio.authex10-minute nonce window, so only a flow with no cross-chain SOL deposit may enable it.2.
flow-yield-distribution: real staking-yield flush— the flow drives the program's genuine yield pipeline:SolanaYieldEmitterToolseeds a staker via the dev-onlydev_seed_staker_yield, then cranksflush_staking_yieldsoliqsol_coreitself packs theStakingRewardinto the outbound buffer (retiring the prior bespokeadd_attestationhand-injection). The scenario opts its own cluster into the epoch warp via itsClusterBuildOptionsdefaults (solanaEpochWarp: true). Because the program derives its own reward ref, the verify matches the depot'sunmappedrow by the staker's native SOL address (not a fixed ref) and asserts the credited WIRE amount equals the emitted reward.flow-yield-distributioncalls the dev-onlydev_seed_staker_yield, so the deployed program must be the development build (anchor build -- --features development). This is wired into the e2e gate by wire-solana'sBUILD.bazel; every other flow runs on either build.Verification
Rebased onto current
master(post wire-sysio #502 merge — the zod-schema / external-cluster-config era) and re-validated on the rebased tip:30040425498: all 13flow-*scenarios passed (0 failed), includingyield-distribution, overriding wire-tools-ts to this PR's branch and wire-solana to its companion (#385); wire-sysio/master carries the merged #502, every other repo at its master default.tsc -bbuild + fulleslint .under master's current lint laws.solanaEpochWarpflag + config resolution, the--upgradeable-programargv branch, the puresolanaWarpArgs(warp on/off),resolveUpgradeAuthority(keypair creation + idempotency), andOppSolProgram(deployer-path helper + the epoch-3 warp arithmetic). The live-validator paths (emitSolanaYield,initialize_global_config) are exercised by the e2e gate above.Companion PRs
decode_account_data) + retirement of nodeop's deadadd_attestationbinding, so the folded IDL is consumed verbatim.custody_mint/custody_decimalsReserve fields, thedev_seed_staker_yieldhelper, and the--features developmentE2E build.🤖 Generated with Claude Code
https://claude.ai/code/session_015CbgvM8EhrPL1VjX8RhNze