Skip to content

Commit

Permalink
Merge pull request #20 from hirosystems/chore/wrap-up
Browse files Browse the repository at this point in the history
Final improvements before audit
  • Loading branch information
Ludo Galabru authored Nov 1, 2023
2 parents 8efde1e + bf57966 commit 13f2744
Show file tree
Hide file tree
Showing 26 changed files with 485 additions and 112 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
**/settings/Testnet.toml
**/.cache/**
history.txt
relayer/target
example/relayer/target
.DS_Store
node_modules

Expand Down
59 changes: 22 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,66 +122,51 @@ The operator will start fetching prices from the Pyth network Price API and subm

### Onchain

The `pyth-oracle-v1` contract is exposing the following read-only method:
The `pyth-helper-v1` contract is exposing the following method:

```clarity
(define-read-only (read-price-feed
(define-public (read-price
(price-feed-id (buff 32))))
```

That can be consumed with the following invocation:

```clarity
(contract-call?
'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.pyth-oracle-v1 ;; Address of the oracle contract
read-price-feed
'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.pyth-helper-v1 ;; Address of the helper contract
read-price
0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b)
```

The authenticity of the price feeds is verified during their ingestion, making the cost of queries as light as possible.

Each Pyth Network price feed is referred to via a unique ID. Price feeds also have different IDs in mainnets than testnets or devnets. The full list of price feeds is listed on the [pyth.network website](https://pyth.network/price-feeds/). The price feed IDs page lists the ID of each available price feed on every chain where they are available. To use a price feed on-chain, look up its ID using these pages, then store the feed ID in your program for price feed queries.

Price Feeds usage and best practices are described on the [pyth.network developer documentation website](https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices).
Price Feed usage and best practices are described on the [pyth.network developer documentation website](https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices).

#### Prices currently supported on Testnet and Mainnet

#### Prices currently supported on Testnet

| Pair | Price Feed ID |
|---------|--------------------------------------------------------------------|
| STX-USD | 0xec7a775f46379b5e943c3526b1c8d54cd49749176b0b98e02dde68d1bd335c17 |

#### Prices currently supported on Mainnet

| Pair | Price Feed ID |
|---------|--------------------------------------------------------------------|
| STX-USD | 0xec7a775f46379b5e943c3526b1c8d54cd49749176b0b98e02dde68d1bd335c17 |
| BTC-USD | 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43 |
| ETH-USD | 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace |

Feel free to open an issue on this repo if more prices are required for your application. The full list of prices is available [here](https://pyth.network/price-feeds/).
The full list of prices is available [here](https://pyth.network/price-feeds/).

### Offchain

For every new price recorded and stored on chain, the `pyth-oracle-v1` is emitting an event with the following shape:
For every new price recorded and stored on chain, the `pyth-store-v1` is emitting an event with the following shape:

```clarity
(print {
type: "price-feed",
action: "updated",
data: {
attestation-time: u1686854317,
conf: u2064471426,
ema-conf: u1891952230,
ema-price: 2507095440000,
expo: 4294967288,
prev-conf: u2064471426,
prev-price: 2515455528574,
prev-publish-time: u1686854316,
price: 2515455528574,
publish-time: u1686854317,
status: u1
} })
{
type: "price-feed",
action: "updated",
data: {
price-identifier: 0xec7a775f46379b5e943c3526b1c8d54cd49749176b0b98e02dde68d1bd335c17,
price: 46098556,
conf: u37359,
ema-price: 46167004,
ema-conf: u36191,
expo: -8,
publish-time: u1695751649,
prev-publish-time: u1695751648
}
}
```

These events can be observed using [Chainhook](https://github.com/hirosystems/chainhook), using the `print` predicates.
Expand Down
15 changes: 9 additions & 6 deletions contracts/pyth-governance-v1.clar
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,21 @@
;; Error parsing PGTM
(define-constant ERR_INVALID_PTGM (err u4007))

(define-data-var governance-data-source
{ emitter-chain: uint, emitter-address: (buff 32) }
{ emitter-chain: u0, emitter-address: 0x5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e })
(define-data-var prices-data-sources
(list 255 { emitter-chain: uint, emitter-address: (buff 32) })
(list
{ emitter-chain: u1, emitter-address: 0x6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25 }
{ emitter-chain: u26, emitter-address: 0xf8cd23c2ab91237730770bbea08d61005cdda0984348f3f6eecb559638c0bba0 }
{ emitter-chain: u26, emitter-address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71 }))
(define-data-var fee-value
{ mantissa: uint, exponent: uint }
{ mantissa: u1, exponent: u1 })
(define-data-var price-data-sources (buff 32) 0x)
(define-data-var governance-data-source
{ emitter-chain: uint, emitter-address: (buff 32) }
{ emitter-chain: u0, emitter-address: 0x0000000000000000000000000000000000000000000000000000000000000000 }) ;; TODO: set initial value
(define-data-var fee-recipient-address principal tx-sender)

(define-data-var last-sequence-processed uint u0) ;; TODO: set initial value

(define-data-var prices-data-sources (list 255 { emitter-chain: uint, emitter-address: (buff 32) }) (list))

(define-map execution-plans uint {
pyth-oracle-contract: principal,
Expand Down
19 changes: 10 additions & 9 deletions contracts/pyth-helper-v1.clar
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

(define-public (verify-and-update-price (pnau-bytes (buff 8192)))
(contract-call? .pyth-oracle-v1 verify-and-update-price-feeds
pnau-bytes
{
pyth-storage-contract: .pyth-store-v1,
pyth-decoder-contract: .pyth-pnau-decoder-v1,
wormhole-core-contract: .wormhole-core-v1
}))

;; (define-public (verify-and-update-price-feeds
;; (price-feed-bytes (buff 8192)))
;; (contract-call? .pyth-oracle-v1 verify-and-update-price-feeds
;; price-feed-bytes
;; {
;; pyth-storage-contract: .pyth-store-v1,
;; pyth-decoder-contract: .pyth-pnau-decoder-v1,
;; wormhole-core-contract: .wormhole-core-v1
;; }))
(define-public (read-price (price-feed-id (buff 32)))
(contract-call? .pyth-oracle-v1 read-price-feed price-feed-id .pyth-store-v1))
2 changes: 1 addition & 1 deletion contracts/pyth-oracle-v1.clar
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
;; Generic error
(define-constant ERR_PANIC (err u0))
;; Balance insufficient for handling fee
(define-constant ERR_BALANCE_INSUFFICIENT (err u4002))
(define-constant ERR_BALANCE_INSUFFICIENT (err u402))

(define-public (read-price-feed
(price-feed-id (buff 32))
Expand Down
5 changes: 5 additions & 0 deletions contracts/pyth-store-v1.clar
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
publish-time: (get publish-time entry),
prev-publish-time: (get prev-publish-time entry)
})
(print {
type: "price-feed",
action: "updated",
data: entry
})
(map-set timestamps (get price-identifier entry) (get publish-time entry))
u1)
u0))
Expand Down
17 changes: 10 additions & 7 deletions contracts/wormhole/wormhole-core-v1.clar
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
;; @param vaa-bytes:
(define-read-only (parse-vaa (vaa-bytes (buff 8192)))
(let ((cursor-version (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-8 { bytes: vaa-bytes, pos: u0 })
ERR_VAA_PARSING_VERSION))
ERR_VAA_PARSING_VERSION))
(cursor-guardian-set-id (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-32 (get next cursor-version))
ERR_VAA_PARSING_GUARDIAN_SET))
(cursor-signatures-len (unwrap! (contract-call? 'SP2J933XB2CP2JQ1A4FGN8JA968BBG3NK3EKZ7Q9F.hk-cursor-v2 read-uint-8 (get next cursor-guardian-set-id))
Expand Down Expand Up @@ -176,7 +176,7 @@
(asserts! (is-eq (get version (get vaa message)) u1)
ERR_VAA_CHECKS_VERSION_UNSUPPORTED)
;; Ensure that the count of valid signatures is >= 13
(asserts! (>= (len (get result signatures-from-active-guardians)) QUORUM)
(asserts! (>= (len (get result signatures-from-active-guardians)) QUORUM)
ERR_VAA_CHECKS_THRESHOLD_SIGNATURE)
;; Good to go!
(ok (get vaa message)))))
Expand Down Expand Up @@ -206,8 +206,9 @@
(var-set guardian-set-initialized true)
;; Emit Event
(print {
object: "guardian-set",
action: "updated",
type: "guardian-set",
action: "updated",
id: set-id,
data: { guardians-eth-addresses: eth-addresses, guardians-public-keys: uncompressed-public-keys }})
(ok {
vaa: vaa,
Expand Down Expand Up @@ -293,9 +294,11 @@

;; @desc Convert an uncompressed public key (64 bytes) into a compressed public key (33 bytes)
(define-private (compress-public-key (uncompressed-public-key (buff 64)))
(let ((x-coordinate (unwrap-panic (slice? uncompressed-public-key u0 u32)))
(y-coordinate-parity (buff-to-uint-be (unwrap-panic (element-at? uncompressed-public-key u63)))))
(unwrap-panic (as-max-len? (concat (if (is-eq (mod y-coordinate-parity u2) u0) 0x02 0x03) x-coordinate) u33))))
(if (is-eq 0x uncompressed-public-key)
0x
(let ((x-coordinate (unwrap-panic (slice? uncompressed-public-key u0 u32)))
(y-coordinate-parity (buff-to-uint-be (unwrap-panic (element-at? uncompressed-public-key u63)))))
(unwrap-panic (as-max-len? (concat (if (is-eq (mod y-coordinate-parity u2) u0) 0x02 0x03) x-coordinate) u33)))))

(define-private (is-eth-address-matching-public-key (uncompressed-public-key (buff 64)) (eth-address (buff 20)))
(is-eq (unwrap-panic (slice? (keccak256 uncompressed-public-key) u12 u32)) eth-address))
Expand Down
Loading

0 comments on commit 13f2744

Please sign in to comment.