From 01985a8c31662e49d5f8bd97a438b8ec87bd2ea5 Mon Sep 17 00:00:00 2001 From: David Meister Date: Mon, 29 Jun 2026 05:57:03 +0000 Subject: [PATCH 1/4] fix(interface/docs): view mutability, return names, meta description, and eval-order comments - IGoverned.governanceSettings(): add missing `view` mutability (#101) - IDineroFlrEth: rename ethAmount/tokenAmount returns to ethPerFlreth18/flrethPerEth18 to reflect ratio semantics (#100) - LibFlareFtsoSubParser sflr-exchange-rate meta: specify 0 inputs and clarify sFLR-per-FLR direction with example value (#95, #104) - LibOpFtsoCurrentPricePair.run: add inline comments explaining the index-shuffle evaluation order (symbolB fetched first, then symbolA) to prevent future inversion during maintenance (#103) Closes #95 Closes #100 Closes #101 Closes #103 Closes #104 Co-Authored-By: Claude --- src/interface/IDineroFlrEth.sol | 4 ++-- src/interface/IGoverned.sol | 2 +- src/lib/op/LibOpFtsoCurrentPricePair.sol | 8 ++++++-- src/lib/parse/LibFlareFtsoSubParser.sol | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/interface/IDineroFlrEth.sol b/src/interface/IDineroFlrEth.sol index 159a1ff..c8c9fbf 100644 --- a/src/interface/IDineroFlrEth.sol +++ b/src/interface/IDineroFlrEth.sol @@ -5,9 +5,9 @@ pragma solidity ^0.8.25; interface IDineroFlrEth { //slither-disable-start naming-convention //forge-lint: disable-next-line(mixed-case-function) - function LSTPerToken() external view returns (uint256 ethAmount); + function LSTPerToken() external view returns (uint256 ethPerFlreth18); //slither-disable-end //forge-lint: disable-next-line(mixed-case-function) - function tokensPerLST() external view returns (uint256 tokenAmount); + function tokensPerLST() external view returns (uint256 flrethPerEth18); } diff --git a/src/interface/IGoverned.sol b/src/interface/IGoverned.sol index c854b08..fb78f68 100644 --- a/src/interface/IGoverned.sol +++ b/src/interface/IGoverned.sol @@ -7,7 +7,7 @@ import {IGovernanceSettings} from "../vendor/flare-smart-contracts/userInterface interface IGoverned { function governance() external view returns (address); - function governanceSettings() external returns (IGovernanceSettings); + function governanceSettings() external view returns (IGovernanceSettings); function executeGovernanceCall(bytes4 selector) external; } diff --git a/src/lib/op/LibOpFtsoCurrentPricePair.sol b/src/lib/op/LibOpFtsoCurrentPricePair.sol index 5d98aa3..d99d9f3 100644 --- a/src/lib/op/LibOpFtsoCurrentPricePair.sol +++ b/src/lib/op/LibOpFtsoCurrentPricePair.sol @@ -43,16 +43,20 @@ library LibOpFtsoCurrentPricePair { function run(OperandV2 operand, StackItem[] memory inputs) internal view returns (StackItem[] memory) { uint256 symbolA; assembly ("memory-safe") { - // Truncating from 3 inputs to 2, so we can forward directly to the - // `ftsoCurrentPriceUsd` opcode. + // Advance the pointer past the length slot so the virtual 2-element + // array starts at inputs[1]=symbolB. Save symbolA so it can be + // restored for the second fetch. inputs := add(inputs, 0x20) symbolA := mload(inputs) mstore(inputs, 2) } + // symbolB is now at inputs[0]; fetch its price first. StackItem[] memory outputsB = LibOpFtsoCurrentPriceUsd.run(operand, inputs); assembly ("memory-safe") { + // Replace symbolB with symbolA so the second fetch uses symbolA. mstore(add(inputs, 0x20), symbolA) } + // symbolA is now at inputs[0]; fetch its price second. StackItem[] memory outputsA = LibOpFtsoCurrentPriceUsd.run(operand, inputs); Float priceA; diff --git a/src/lib/parse/LibFlareFtsoSubParser.sol b/src/lib/parse/LibFlareFtsoSubParser.sol index 290d6dc..ee2ea85 100644 --- a/src/lib/parse/LibFlareFtsoSubParser.sol +++ b/src/lib/parse/LibFlareFtsoSubParser.sol @@ -27,8 +27,10 @@ library LibFlareFtsoSubParser { "ftso-current-price-pair", "Returns the current price of the given token pair according to the FTSO. Accepts 3 inputs, the symbol string used by the FTSO for the base token, the symbol string used by the FTSO for the quote token and the timeout in seconds. The price is rounded down if it does not fit in a Rainlang number. The timeout will be used to determine if the price is stale and revert if it is. Note that the pair price is derived from two separate FTSO prices mechanically and is not provided directly by the FTSO." ); - meta[SUB_PARSER_WORD_SFLR_EXCHANGE_RATE] = - AuthoringMetaV2("sflr-exchange-rate", "Returns the current exchange rate of FLR to SFLR."); + meta[SUB_PARSER_WORD_SFLR_EXCHANGE_RATE] = AuthoringMetaV2( + "sflr-exchange-rate", + "Returns the current sFLR-per-FLR exchange rate as a Rain Float. Accepts 0 inputs. The value is the number of sFLR shares equivalent to 1 FLR of pooled liquidity (e.g. ~0.877 means 1 FLR buys 0.877 sFLR). To convert in the FLR-per-sFLR direction, take the reciprocal." + ); return abi.encode(meta); } } From 8833fca3557a7dc6f218bb5986e828bd74b52183 Mon Sep 17 00:00:00 2001 From: David Meister Date: Mon, 29 Jun 2026 09:08:44 +0000 Subject: [PATCH 2/4] fix(ci): copy-artifacts [3b-attempt] meta artifact mismatch (non-reproducible locally; retrigger) From 98c534358994c57406845be6750f0aa77a43b011 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 2 Aug 2026 13:17:44 +0000 Subject: [PATCH 3/4] fix(ci): copy-artifacts [3b-attempt] regenerate meta and pointers Regenerate the committed artifacts from the build on the post-merge tree, rather than text-merging them. Recipe is the repo's own `script/build.sh`, which delegates to the `rain-flare-prelude` nix task (flake.nix): forge script --silent ./script/BuildAuthoringMeta.sol rain meta build -i <(cat meta/FlareFtsoSubParserAuthoringMeta.rain.meta) \ -m authoring-meta-v2 -t cbor -e deflate -l none \ -o meta/FlareFtsoWords.rain.meta forge script --silent ./script/Build.sol forge fmt This is the same recipe the rainix copy-artifacts reusable runs. What changed and why: the merge integrated a new `sflr-exchange-rate` authoring meta description, which flows into both meta blobs and, through keccak256 of meta/FlareFtsoWords.rain.meta, into DESCRIBED_BY_META_HASH. FlareFtsoWords.describedByMetaHash() returns that constant, so it is part of the deployed bytecode, so BYTECODE_HASH moves with it: meta/FlareFtsoSubParserAuthoringMeta.rain.meta 1536 -> 1664 bytes meta/FlareFtsoWords.rain.meta 521 -> 595 bytes DESCRIBED_BY_META_HASH 0x4ccb316f... -> 0x1bff202a... BYTECODE_HASH 0x69ffc416... -> 0x358d8e81... Because DESCRIBED_BY_META_HASH is compiled into the contract whose codehash becomes BYTECODE_HASH, converging from the merged tree takes two prelude passes; a third pass is a no-op, so this is a genuine fixed point and the copy-artifacts diff check is stable. Verified the regeneration is not a silent no-op: BYTECODE_HASH was set to 0xdeadbeef...deadbeef and the prelude restored it to 0x358d8e811b035af26e4cf1bd71f901057474799487777603aaa6ac620842bcf0. Co-Authored-By: Claude --- .../FlareFtsoSubParserAuthoringMeta.rain.meta | Bin 1536 -> 1664 bytes meta/FlareFtsoWords.rain.meta | Bin 521 -> 595 bytes src/generated/FlareFtsoWords.pointers.sol | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meta/FlareFtsoSubParserAuthoringMeta.rain.meta b/meta/FlareFtsoSubParserAuthoringMeta.rain.meta index fdbf3f551a46ef1a8c34a6661d931a8b91d9053c..1e055294de9aec73bb8c6ed51efb4166fad2a509 100644 GIT binary patch delta 274 zcmXYsu}%Xq5JUlS9rTpb0n)`vs?elJlZqcKHd}*_sd<{uv1bbTe{WNcm0*;I7mpP}U?m(lY2_Lzsy;Rw89JBPs*}({X~$!r LDlR6m_N<0RItrP3sd@?- z`Q-|^iFuU@#UN$H8Hq)y#R|#!ML?<`KQBe0BwxW0WP+Z8u4^1k(h6{|br5bnbX`qySk0A$XkCQ%#T4Fc4ine#jg_YN7=W%Mm2h69TDS z?(4*p)>_BTj>j#zz;EUsFt*d}f=b(!xNHt>?3p)jX5P!i@dr-CUz~{F91lM~0e^YZ zaqv|eiO_L1kZG}sL0_Evd^jF{Hd`P^ashaaFwwxb9{;5r3J|)n*#|YGU%7;b;EF6!5 z-9^v1^Uc%J8ouP#*NO`wZT23fk!0%{I`Td6*2^S=BE{4AIWItu?OHk0Dr?8gVagB# z`HjgF8p4((_+WQ`n=EveD*T=*t*}ZQ=UVG5fBigv4GO8#NT4S7Blrsc!j zdc`xD+;$b=;EDGpSSG6xruE*+Z7L&5GpUyMM!cMiShU+H8}n`xzKEI}o?3yhRwVnx zyJ#dWbts~~$z>&F@ZJiEH4@f_N9oB+lck`=kV+~i`8_HbwBSaARtM;Ci?oaHx!@Jn zs~UbXT-NWeuKvI^ag@&UbxMCN&HFT4F^?-UPTR}%ipIvL4@Z`f6XeE-3B(xn#cx~^ JxGIz60VO-@95(;} delta 496 zcmVHp-6RiX;sJV5qg7?lpP0!YdJuEq7O;bXm)mYW_9_31^mqdes>vuy+D6^*9wP9 zM(gcU)p~;x$umfYaFBr?+b>Y0AhZR4*x5aLkZ_;wO6x$z`dvB~ z@aA^=y@trGZ(GU($|3~B?FL!%gHjVIB5#vpji z&CBu{zLnNHB{L&$_JL-Q($)>M6nc;`q)7%vN)F?f{}_7Io$^*I=cb}z=OG3Pds`;7 zgjy2#Xm|gHj9W(){>qhhSY?fCqjgQbR=>~Xi*LSXZeT!y{5)zynUB%672yy_PM&Xb zvIz4w@6*@JO2!H)Eo-nf*3g9!dgZ6NGl?A7HZR3`2_}(h)xuJ;nUpA?EeM0{#N_UW6`_E&?Tq0_ Date: Sat, 15 Aug 2026 13:44:22 +0000 Subject: [PATCH 4/4] chore: re-vet at new head after QA evidence and linkage repair Body now carries the QA-GUIDE section 8 evidence block. Closes narrowed to issue 100 only: issues 95, 101, 103 and 104 were fixed independently on main before this branch merged it and are already closed, so their Closes were weakened to Refs. Co-Authored-By: Claude Opus 5