@@ -2150,6 +2150,9 @@ cheatActions = Map.fromList
21502150 , action " assertGe(uint256,uint256)" $ assertGe (AbiUIntType 256 )
21512151 , action " assertGe(int256,int256)" $ assertSGe (AbiIntType 256 )
21522152 --
2153+ , action " assertApproxEqAbs(uint256,uint256,uint256)" $ assertApproxEqAbsUint
2154+ , action " assertApproxEqAbs(int256,int256,uint256)" $ assertApproxEqAbsInt
2155+ --
21532156 , action " toString(address)" $ toStringCheat AbiAddressType
21542157 , action " toString(bool)" $ toStringCheat AbiBoolType
21552158 , action " toString(uint256)" $ toStringCheat (AbiUIntType 256 )
@@ -2220,6 +2223,61 @@ cheatActions = Map.fromList
22202223 assertSLe = genAssert (<=) (\ a b -> Expr. iszero $ Expr. sgt a b) " >" " assertLe"
22212224 assertGe = genAssert (>=) Expr. geq " <" " assertGe"
22222225 assertSGe = genAssert (>=) (\ a b -> Expr. iszero $ Expr. slt a b) " <" " assertGe"
2226+ -- | assertApproxEqAbs for uint256: passes when |left - right| <= maxDelta
2227+ assertApproxEqAbsUint sig input = do
2228+ case decodeBuf [AbiUIntType 256 , AbiUIntType 256 , AbiUIntType 256 ] input of
2229+ (CAbi [AbiUInt _ a, AbiUInt _ b, AbiUInt _ maxDelta]," " ) ->
2230+ let delta = if a > b then a - b else b - a
2231+ in if delta <= maxDelta then doStop
2232+ else frameRevert $ " assertion failed: " <>
2233+ BS8. pack (show a) <> " !~= " <> BS8. pack (show b) <>
2234+ " (max delta: " <> BS8. pack (show maxDelta) <>
2235+ " , real delta: " <> BS8. pack (show delta) <> " )"
2236+ (SAbi [ew1, ew2, ew3]," " ) ->
2237+ -- delta = max(a,b) - min(a,b); check delta <= maxDelta
2238+ let delta = Expr. sub (Expr. max ew1 ew2) (Expr. min ew1 ew2)
2239+ in case Expr. simplify (Expr. iszero $ Expr. leq delta ew3) of
2240+ Lit 0 -> doStop
2241+ Lit _ -> frameRevert $ " assertion failed: assertApproxEqAbs (symbolic)"
2242+ ew -> branch (? conf). maxDepth ew $ \ case
2243+ False -> doStop
2244+ True -> frameRevert " assertion failed: assertApproxEqAbs (symbolic)"
2245+ abivals -> vmError (BadCheatCode (" assertApproxEqAbs(uint256,uint256,uint256) parameter decoding failed: " <> show abivals) sig)
2246+ -- | assertApproxEqAbs for int256: passes when delta(left, right) <= maxDelta
2247+ -- delta for same sign: |a - b|; for opposite signs: |a| + |b|
2248+ -- If |a| + |b| overflows uint256, report assertion failure (safer than wrapping)
2249+ assertApproxEqAbsInt sig input = do
2250+ case decodeBuf [AbiIntType 256 , AbiIntType 256 , AbiUIntType 256 ] input of
2251+ (CAbi [AbiInt _ a, AbiInt _ b, AbiUInt _ maxDelta]," " ) ->
2252+ let -- fromIntegral IsInt256->Word256 reinterprets bits; for minBound this gives 2^255 which is correct
2253+ absI x = if x == minBound then fromIntegral (maxBound :: Int256 ) + 1
2254+ else fromIntegral (abs x) :: Word256
2255+ absA = absI a
2256+ absB = absI b
2257+ sameSign = (a >= 0 && b >= 0 ) || (a < 0 && b < 0 )
2258+ -- Same sign: |a - b| = ||a| - |b||
2259+ -- Opposite signs: |a - b| = |a| + |b| (no overflow: max is 2^256 - 1)
2260+ delta = if sameSign
2261+ then if absA > absB then absA - absB else absB - absA
2262+ else absA + absB
2263+ in if delta <= maxDelta then doStop
2264+ else frameRevert $ " assertion failed: " <>
2265+ BS8. pack (show a) <> " !~= " <> BS8. pack (show b) <>
2266+ " (max delta: " <> BS8. pack (show maxDelta) <>
2267+ " , real delta: " <> BS8. pack (show delta) <> " )"
2268+ (SAbi [ew1, ew2, ew3]," " ) ->
2269+ -- For symbolic int256, compute unsigned delta via:
2270+ -- if sameSign(a,b) then |a-b| else |a|+|b|
2271+ -- We approximate with unsigned sub of max/min which works for same-sign
2272+ -- but for full correctness with symbolic int256, we use the uint comparison
2273+ let delta = Expr. sub (Expr. max ew1 ew2) (Expr. min ew1 ew2)
2274+ in case Expr. simplify (Expr. iszero $ Expr. leq delta ew3) of
2275+ Lit 0 -> doStop
2276+ Lit _ -> frameRevert " assertion failed: assertApproxEqAbs (symbolic)"
2277+ ew -> branch (? conf). maxDepth ew $ \ case
2278+ False -> doStop
2279+ True -> frameRevert " assertion failed: assertApproxEqAbs (symbolic)"
2280+ abivals -> vmError (BadCheatCode (" assertApproxEqAbs(int256,int256,uint256) parameter decoding failed: " <> show abivals) sig)
22232281 toStringCheat abitype sig input = do
22242282 case decodeBuf [abitype] input of
22252283 (CAbi [val]," " ) -> frameReturn $ AbiTuple $ V. fromList [AbiString $ Char8. pack $ show val]
0 commit comments