Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ env:
PYTHON_VERSION: '3.11.11'

jobs:
test_pyth_mock:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@21bacf9f516cc52b91a71c066d9b3446623cdede # master, 2026-09-16
with:
version: stable
- name: Run Pyth mock tests
working-directory: e2e/pyth_mock
run: forge test
- name: Run Pyth ABI fixtures
run: python3 contracts/tests/fixtures/pyth_abi_fixtures_test.py

build_and_test_smart_contracts:
runs-on: ubuntu-22.04
steps:
Expand Down
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,55 @@ feed with `set_oracle`.
alongside the mainnet manifest, which oracle instance/administrator is being used and who controls
it — this project does not deploy or administer that upstream feed itself.

### Pyth / NAC Staged Activation Order (Etherlink L2)

`TezFinOracle`'s Etherlink/Pyth upstream lookup
is fail-closed by design: `pythCore`, `pythMaxAgeWord`, and `feedIds` are **not** populated in the
constructor (only a placeholder 60-second `pythMaxAgeWord` is), so `getPrice`/`getValidatedPrice`
reject every non-override asset until an admin finishes configuring them. The following order is
mandatory and must be reproduced by the deployment runner and any governance payload:

```text
originate TezFinOracle
-> setPythCore(pythCoreEvmAddress)
-> setPythMaxAge(maxAgeWord)
-> setFeedIds([{asset, feedId, targetDecimals}, ...])
-> configurePriceBounds(...) (per Comptroller/cToken)
-> configureMaxPriceAge(...) (per Comptroller)
-> enable market (supportMarket / unpause)
```

If a step is skipped, `getPrice`/`getValidatedPrice` fails closed with a specific error instead of
silently returning stale or zero data:

| Skipped step | `getPrice` / `getValidatedPrice` error |
|---|---|
| `setFeedIds` for the asset | `UNSUPPORTED_PYTH_ASSET` |
| `setPythCore` | `PYTH_CORE_NOT_CONFIGURED` |
| `configurePriceBounds` | `PRICE_BOUNDS_NOT_CONFIGURED` |
| `configureMaxPriceAge` | `MAX_PRICE_AGE_NOT_CONFIGURED` |

This order and every error in the table above are covered by
[`contracts/tests/TezFinOracleTest.py`](contracts/tests/TezFinOracleTest.py).

### Pyth confidence and proxy risk policy

The production oracle accepts a Pyth update only when the confidence interval is
no more than 25% of the raw price:

```text
conf * 4 <= rawPrice
```

The L2 asset mappings below are explicit proxies, not independent price feeds:

- `tzBTC-USD` uses the BTC/USD Pyth feed. This does not detect a tzBTC/BTC depeg.
- `USDtz-USD` and `USDt-USD` use the USDT/USD Pyth feed. This does not prove or
detect a USDtz/USDT or USDt/USDT peg failure.

These proxy mappings must be treated as a governance and risk-policy decision;
they are not evidence that the wrapped asset maintains its intended peg.

## Post-Deployment Admin Handoff (Mainnet)

After origination, every contract (`Governance`, `TezFinOracle`) is initially administered by the
Expand Down
20 changes: 20 additions & 0 deletions TezFinBuild/deploy_result/deploy.shadownet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"OriginatorAddress": "tz1XTWbfhyWK9xmPAa6TyQUSv437JFgZDzgA",
"chainId": "NetXtLrzvQDobza",
"evmChainId": 127823,
"network": "https://michelson.etherlink.shadownet.octez.io",
"networkProfile": "shadownet",
"PythCore": "0x2880aB155794e7179c9eE2e38200202908C17B43",
"PythMaxAgeSeconds": 60,
"TezFinMaxPriceAgeSeconds": 60,
"PythFeedIds": {
"BTC_USD": "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
"XTZ_USD": "0x0affd4b8ad136a21d79bc82450a325ee12ff55a235abc242666e423b8bcffd03",
"USDT_USD": "0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b"
},
"PriceOracle": "KT1FVzw3ogGSq4Djde17MJqVKd6DZReo8MNb",
"USDt": "KT1JhouNkvVaHhY9hc9yCN8zcqa6uEfoCY9y",
"USDtz": "KT1KgUM85JcH3eAFqWNjhsgfRmKcAeds9X4r",
"tzBTC": "KT1VyfHmnP3awrxUdKFYXUtWhr8SAVqiHJRK",
"TezFinOracle": "KT1StW5tmRTZxJY72CLXiv1FKRFdVa3hsvsX"
}
Loading
Loading