#37276 [SC-Medium] Redstone's price feed is used incorrectly.
Submitted on Dec 1st 2024 at 11:03:07 UTC by @jasonxiale for IOP | Fluid Protocol
Report ID: #37276
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/Hydrogen-Labs/fluid-protocol/tree/main/contracts/oracle-contract/src/main.sw
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
In current implementation for oracle-contract.get_price
, while function is_pyth_price_stale_or_outside_confidence
return true in main.sw#L88, Redstone price feed will be used.
However there is a flaw when using Redstone price feed that might lead stale price being used.
Vulnerability Details
According to oracle-contract.get_price
, when redstone is used, redstone.read_timestamp
will be used as the price 's publish timestamp.
And redstone.read_timestamp
will be checked against with current_time
in main.sw#L107
The issue is that redstone.read_timestamp
uses Unix timestamp, but Fule's timestamp
function returns TAI64 format timestamp
Quoting from timestamp's implementation
From above code, we can see that timestamp()
returns [The TAI64 timestamp of the current block.] (https://github.com/FuelLabs/sway/blob/6d9065b8d762a39eb475562426a2d4ed17d92d00/sway-lib-std/src/block.sw#L47)
According to redstone_adapter.read_timestamp, the function uses
storage.timestamp
as return value.And
storage.timestamp
is written by redstone_adapter.sw#L139 inredstone_adapter.overwrite_prices
function.redstone_adapter.overwrite_prices
is called byredstone_adapter.write_prices
in redstone_adapter.sw#L96Now we'll check how
timestamp
is returned in redstone_adapter.sw#L95In redstone_adapter.process_payload, a
config
var is created withconfig.block_timestamp
set toget_unix_timestamp()
get_unix_timestamp() is defined as:
From here, we know that config.block_timestamp
is UNIX time.
Back to
redstone_adapter.process_payload
, in redstone_adapter.sw#L150,process_input
is called, andprocess_input
is defined in processor.process_input.
In processor.sw#L32,
timestamp
is returned byconfig.validate_timestamps
function.config.validate_timestamps
is defined in config_validation.sw#L27-L43
In config_validation.sw#L28-L29, the payload's timestamp and self.block_timestamp(which is UNIX timestamp) are passed to
validate_timestamp
function.According to validate_timestamp's implemention, we can get see that
payload's timestamp
in step9 should be UNIX timestamp format.