feat(target_chains/fuel): add governance contract (#1518)

* add governance contract

* add fuel ci

* add rust-toolchain

* add executes_governance_instruction test

* add test for SetValidPeriod

* add test for AuthorizeGovernanceDataSourceTransfer

* remove SetWormholeAddress

* add test for SetDataSources

* remove WormholeAddressSetEvent

* remove SetWormholeAddress

* remove SetWormholeAddressPayload

* remove SetWormholeAddressPayload and SetWormholeAddress imports

* remove GovernanceAction::SetWormholeAddress

* address comments

* refactor test

* add comments
This commit is contained in:
Daniel Chew 2024-05-09 17:42:28 +01:00 committed by GitHub
parent 6e0bd0569b
commit cf7987f4c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 1808 additions and 219 deletions

35
.github/workflows/ci-fuel-contract.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: Test Fuel Contract
on:
pull_request:
paths:
- target_chains/fuel/**
push:
branches:
- main
paths:
- target_chains/fuel/**
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: target_chains/fuel/contracts/
steps:
- uses: actions/checkout@v2
- name: Install Fuel toolchain
run: |
curl https://install.fuel.network | sh
echo "$HOME/.fuelup/bin" >> $GITHUB_PATH
- name: Build with Forc
run: forc build --verbose
- name: Run tests with Forc
run: forc test --verbose
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

View File

@ -4,7 +4,11 @@ use {
merkle::MerkleTree,
Accumulator,
},
hashers::keccak256_160::Keccak160,
hashers::{
keccak256::Keccak256,
keccak256_160::Keccak160,
Hasher,
},
messages::{
FeedId,
Message,
@ -27,6 +31,7 @@ use {
byteorder::BigEndian,
libsecp256k1::{
Message as libsecp256k1Message,
PublicKey,
RecoveryId,
SecretKey,
Signature,
@ -96,6 +101,19 @@ pub fn dummy_guardians() -> Vec<SecretKey> {
result
}
pub fn dummy_guardians_addresses() -> Vec<[u8; 20]> {
let guardians = dummy_guardians();
guardians
.iter()
.map(|x| {
let mut result: [u8; 20] = [0u8; 20];
let pubkey = &PublicKey::from_secret_key(x).serialize()[1..];
result.copy_from_slice(&Keccak256::hashv(&[&pubkey])[12..]);
result
})
.collect()
}
pub fn create_dummy_feed_id(value: i64) -> FeedId {
let mut dummy_id = [0; 32];
dummy_id[0] = value as u8;
@ -271,7 +289,6 @@ pub fn create_vaa_from_payload(
..Default::default()
};
(header, body).into()
}

View File

@ -134,6 +134,12 @@ version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "arrayref"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]]
name = "ascii"
version = "0.9.3"
@ -182,7 +188,7 @@ dependencies = [
"Inflector",
"async-graphql-parser",
"darling 0.14.4",
"proc-macro-crate",
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 1.0.109",
@ -360,6 +366,15 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -387,6 +402,15 @@ dependencies = [
"wyz",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@ -396,22 +420,98 @@ dependencies = [
"generic-array",
]
[[package]]
name = "borsh"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
dependencies = [
"borsh-derive",
"hashbrown 0.13.2",
]
[[package]]
name = "borsh-derive"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
dependencies = [
"borsh-derive-internal",
"borsh-schema-derive-internal",
"proc-macro-crate 0.1.5",
"proc-macro2",
"syn 1.0.109",
]
[[package]]
name = "borsh-derive-internal"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "borsh-schema-derive-internal"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"sha2",
"sha2 0.10.8",
"tinyvec",
]
[[package]]
name = "bstr"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytemuck"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]]
name = "byteorder"
version = "1.5.0"
@ -517,11 +617,11 @@ checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3"
dependencies = [
"bs58",
"coins-core",
"digest",
"hmac",
"digest 0.10.7",
"hmac 0.12.1",
"k256",
"serde",
"sha2",
"sha2 0.10.8",
"thiserror",
]
@ -533,11 +633,11 @@ checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528"
dependencies = [
"bitvec",
"coins-bip32",
"hmac",
"hmac 0.12.1",
"once_cell",
"pbkdf2 0.12.2",
"rand",
"sha2",
"sha2 0.10.8",
"thiserror",
]
@ -550,13 +650,13 @@ dependencies = [
"base64 0.21.7",
"bech32",
"bs58",
"digest",
"digest 0.10.7",
"generic-array",
"hex",
"ripemd",
"serde",
"serde_derive",
"sha2",
"sha2 0.10.8",
"sha3",
"thiserror",
]
@ -713,6 +813,16 @@ dependencies = [
"typenum",
]
[[package]]
name = "crypto-mac"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "ct-logs"
version = "0.8.0"
@ -740,7 +850,7 @@ dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest",
"digest 0.10.7",
"fiat-crypto",
"platforms",
"rustc_version",
@ -911,13 +1021,22 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"block-buffer 0.10.4",
"const-oid",
"crypto-common",
"subtle",
@ -935,6 +1054,12 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
[[package]]
name = "dyn-clone"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "ecdsa"
version = "0.16.9"
@ -942,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
"der",
"digest",
"digest 0.10.7",
"elliptic-curve",
"rfc6979",
"signature",
@ -966,7 +1091,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
dependencies = [
"curve25519-dalek",
"ed25519",
"sha2",
"sha2 0.10.8",
"subtle",
]
@ -984,7 +1109,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
"base16ct",
"crypto-bigint",
"digest",
"digest 0.10.7",
"ff",
"generic-array",
"group",
@ -1054,15 +1179,15 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab"
dependencies = [
"aes",
"ctr",
"digest",
"digest 0.10.7",
"hex",
"hmac",
"hmac 0.12.1",
"pbkdf2 0.11.0",
"rand",
"scrypt",
"serde",
"serde_json",
"sha2",
"sha2 0.10.8",
"sha3",
"thiserror",
"uuid 0.8.2",
@ -1090,10 +1215,19 @@ dependencies = [
]
[[package]]
name = "fastrand"
version = "2.0.2"
name = "fast-math"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
checksum = "2465292146cdfc2011350fe3b1c616ac83cf0faeedb33463ba1c332ed8948d66"
dependencies = [
"ieee754",
]
[[package]]
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "ff"
@ -1451,7 +1585,7 @@ dependencies = [
"rand",
"secp256k1",
"serde",
"sha2",
"sha2 0.10.8",
"zeroize",
]
@ -1474,12 +1608,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89143dd80b29dda305fbb033bc7f868834445ef6b361bf920f0077938fb6c0bc"
dependencies = [
"derive_more",
"digest",
"digest 0.10.7",
"fuel-storage",
"hashbrown 0.13.2",
"hex",
"serde",
"sha2",
"sha2 0.10.8",
]
[[package]]
@ -1633,7 +1767,7 @@ dependencies = [
"itertools 0.12.1",
"serde",
"serde_json",
"sha2",
"sha2 0.10.8",
"thiserror",
"uint",
]
@ -1694,7 +1828,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"serde_with 3.7.0",
"serde_with 3.8.0",
"tempfile",
"tokio",
"which",
@ -1939,13 +2073,34 @@ dependencies = [
"serde",
]
[[package]]
name = "hmac"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
"digest 0.10.7",
]
[[package]]
name = "hmac-drbg"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
dependencies = [
"digest 0.9.0",
"generic-array",
"hmac 0.8.1",
]
[[package]]
@ -2048,7 +2203,7 @@ dependencies = [
"http",
"hyper",
"log",
"rustls 0.21.11",
"rustls 0.21.12",
"rustls-native-certs 0.6.3",
"tokio",
"tokio-rustls 0.24.1",
@ -2129,6 +2284,12 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "ieee754"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c"
[[package]]
name = "indexmap"
version = "1.9.3"
@ -2208,7 +2369,7 @@ dependencies = [
"ecdsa",
"elliptic-curve",
"once_cell",
"sha2",
"sha2 0.10.8",
"signature",
]
@ -2239,6 +2400,54 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "libsecp256k1"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
dependencies = [
"arrayref",
"base64 0.13.1",
"digest 0.9.0",
"hmac-drbg",
"libsecp256k1-core",
"libsecp256k1-gen-ecmult",
"libsecp256k1-gen-genmult",
"rand",
"serde",
"sha2 0.9.9",
"typenum",
]
[[package]]
name = "libsecp256k1-core"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451"
dependencies = [
"crunchy",
"digest 0.9.0",
"subtle",
]
[[package]]
name = "libsecp256k1-gen-ecmult"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809"
dependencies = [
"libsecp256k1-core",
]
[[package]]
name = "libsecp256k1-gen-genmult"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c"
dependencies = [
"libsecp256k1-core",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
@ -2247,9 +2456,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "lock_api"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@ -2335,12 +2544,78 @@ dependencies = [
"tempfile",
]
[[package]]
name = "num"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.18"
@ -2375,6 +2650,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.64"
@ -2428,14 +2709,14 @@ dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
"sha2 0.10.8",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
dependencies = [
"lock_api",
"parking_lot_core",
@ -2443,15 +2724,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.9"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.48.5",
"windows-targets 0.52.5",
]
[[package]]
@ -2466,7 +2747,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
dependencies = [
"digest",
"digest 0.10.7",
]
[[package]]
@ -2475,8 +2756,8 @@ version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
"digest 0.10.7",
"hmac 0.12.1",
]
[[package]]
@ -2602,6 +2883,15 @@ dependencies = [
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
@ -2691,11 +2981,37 @@ dependencies = [
"dotenv",
"fuels",
"hex",
"libsecp256k1",
"pythnet-sdk",
"rand",
"reqwest",
"serde",
"serde_json",
"serde_wormhole",
"sha3",
"tokio",
"wormhole-vaas-serde",
]
[[package]]
name = "pythnet-sdk"
version = "2.0.0"
dependencies = [
"bincode",
"borsh",
"bytemuck",
"byteorder",
"fast-math",
"hex",
"libsecp256k1",
"rand",
"rustc_version",
"serde",
"serde_wormhole",
"sha3",
"slow_primes",
"thiserror",
"wormhole-vaas-serde",
]
[[package]]
@ -2765,11 +3081,11 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.4.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.5.0",
]
[[package]]
@ -2828,7 +3144,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls 0.21.11",
"rustls 0.21.12",
"rustls-pemfile",
"serde",
"serde_json",
@ -2853,7 +3169,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
"hmac",
"hmac 0.12.1",
"subtle",
]
@ -2893,7 +3209,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"
dependencies = [
"digest",
"digest 0.10.7",
]
[[package]]
@ -2913,9 +3229,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.33"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.5.0",
"errno",
@ -2939,9 +3255,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.21.11"
version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring 0.17.8",
@ -3048,6 +3364,30 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "schemars"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 1.0.109",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -3060,10 +3400,10 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d"
dependencies = [
"hmac",
"hmac 0.12.1",
"pbkdf2 0.11.0",
"salsa20",
"sha2",
"sha2 0.10.8",
]
[[package]]
@ -3159,24 +3499,44 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]]
name = "serde"
version = "1.0.198"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.198"
name = "serde_bytes"
version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]]
name = "serde_derive_internals"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "serde_json"
version = "1.0.116"
@ -3212,9 +3572,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.7.0"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a"
checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0"
dependencies = [
"serde",
"serde_derive",
@ -3232,6 +3592,32 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "serde_wormhole"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24b022bf813578a06341fd453c3fd6e64945d9975191193d5d45e8dbd97d1d84"
dependencies = [
"base64 0.13.1",
"itoa",
"serde",
"serde_bytes",
"thiserror",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.8"
@ -3240,7 +3626,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"digest 0.10.7",
]
[[package]]
@ -3249,7 +3635,7 @@ version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
dependencies = [
"digest",
"digest 0.10.7",
"keccak",
]
@ -3268,7 +3654,7 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"digest 0.10.7",
"rand_core",
]
@ -3281,6 +3667,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "slow_primes"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58267dd2fbaa6dceecba9e3e106d2d90a2b02497c0e8b01b8759beccf5113938"
dependencies = [
"num",
]
[[package]]
name = "smallvec"
version = "1.13.2"
@ -3604,7 +3999,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls 0.21.11",
"rustls 0.21.12",
"tokio",
]
@ -3634,6 +4029,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
@ -4179,6 +4583,32 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "wormhole-supported-chains"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f42a80a24212937cc7d7b0ab8115bb87d82f949a1a42f75d500807072c94ba4"
dependencies = [
"serde",
"thiserror",
]
[[package]]
name = "wormhole-vaas-serde"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240c5a6136dc66ecc65097bb6d159e849b5df4ecbbbb220868d0edbdcc568ed3"
dependencies = [
"anyhow",
"bstr",
"schemars",
"serde",
"serde_wormhole",
"sha3",
"thiserror",
"wormhole-supported-chains",
]
[[package]]
name = "wyz"
version = "0.5.1"

View File

@ -16,6 +16,12 @@ reqwest = "0.11.27"
serde_json = "1.0.114"
serde = "1.0.197"
dotenv = "0.15.0"
libsecp256k1 = "0.7.1"
pythnet-sdk = { path = "../../../pythnet/pythnet_sdk", features = ["test-utils"] }
sha3 = "0.10.8"
serde_wormhole = { version ="0.1.0" }
wormhole-vaas-serde = { version = "0.1.0" }
[[bin]]
name = "deploy_pyth"

View File

@ -1,6 +1,6 @@
[[package]]
name = "core"
source = "path+from-root-C3992B43B72ADB8C"
source = "path+from-root-566CA1D5F8BEAFBF"
[[package]]
name = "ownership"
@ -40,5 +40,5 @@ dependencies = ["std"]
[[package]]
name = "std"
source = "git+https://github.com/fuellabs/sway?tag=v0.49.1#2ac7030570f22510b0ac2a7b5ddf7baa20bdc0e1"
source = "git+https://github.com/fuellabs/sway?tag=v0.49.3#0dc6570377ee9c4a6359ade597fa27351e02a728"
dependencies = ["core"]

View File

@ -1,6 +1,6 @@
[toolchain]
channel = "nightly-2024-01-24"
channel = "beta-5"
[components]
forc = "0.49.1"
fuel-core = "0.22.0"
forc = "0.49.3"
fuel-core = "0.22.4"

View File

@ -6,3 +6,4 @@ pub mod price;
pub mod accumulator_update;
pub mod batch_attestation_update;
pub mod update_type;
pub mod governance_instruction;

View File

@ -19,7 +19,7 @@ impl DataSource {
}
#[storage(read)]
pub fn is_valid(
pub fn is_valid_data_source(
self,
is_valid_data_source: StorageKey<StorageMap<DataSource, bool>>,
) -> bool {
@ -28,4 +28,8 @@ impl DataSource {
None => false,
}
}
pub fn is_valid_governance_data_source(self, chain_id: u16, emitter_address: b256) -> bool {
self.chain_id == chain_id && self.emitter_address == emitter_address
}
}

View File

@ -0,0 +1,183 @@
library;
use ::errors::PythError;
use ::data_structures::{data_source::*, price::*, wormhole_light::{StorageGuardianSet, WormholeVM}};
use pyth_interface::data_structures::{data_source::DataSource, price::{PriceFeed, PriceFeedId}, governance_payload::{UpgradeContractPayload, AuthorizeGovernanceDataSourceTransferPayload, RequestGovernanceDataSourceTransferPayload, SetDataSourcesPayload, SetFeePayload, SetValidPeriodPayload}, governance_instruction::{GovernanceInstruction, GovernanceModule, GovernanceAction}};
use std::{bytes::Bytes, hash::Hash};
use std::math::*;
use std::primitive_conversions::{u32::*, u64::*};
pub const MAGIC: u32 = 0x5054474d;
impl GovernanceInstruction {
pub fn new(magic: u32,
module: GovernanceModule,
action: GovernanceAction,
target_chain_id: u16,
payload: Bytes
) -> Self {
Self { magic, module, action, target_chain_id, payload }
}
pub fn parse_governance_instruction(encoded_instruction: Bytes) -> Self {
let mut index = 0;
let magic = u32::from_be_bytes([
encoded_instruction.get(index).unwrap(),
encoded_instruction.get(index + 1).unwrap(),
encoded_instruction.get(index + 2).unwrap(),
encoded_instruction.get(index + 3).unwrap(),
]);
require(magic == MAGIC, PythError::InvalidMagic);
index += 4;
let mod_number = encoded_instruction.get(index).unwrap();
let module = match mod_number {
0 => GovernanceModule::Executor,
1 => GovernanceModule::Target,
2 => GovernanceModule::EvmExecutor,
3 => GovernanceModule::StacksTarget,
_ => GovernanceModule::Invalid,
};
require(match module {
GovernanceModule::Target => true,
_ => false,
}, PythError::InvalidGovernanceTarget);
index += 1;
let action_number = encoded_instruction.get(index).unwrap();
let governance_action = match action_number {
0 => GovernanceAction::UpgradeContract, // Not implemented
1 => GovernanceAction::AuthorizeGovernanceDataSourceTransfer,
2 => GovernanceAction::SetDataSources,
3 => GovernanceAction::SetFee,
4 => GovernanceAction::SetValidPeriod,
5 => GovernanceAction::RequestGovernanceDataSourceTransfer,
_ => GovernanceAction::Invalid,
};
require(match governance_action {
GovernanceAction::Invalid => false,
_ => true,
}, PythError::InvalidGovernanceAction);
index += 1;
let target_chain_id = u16::from_be_bytes([
encoded_instruction.get(index).unwrap(),
encoded_instruction.get(index + 1).unwrap(),
]);
index += 2;
let (_, payload) = encoded_instruction.split_at(index);
GovernanceInstruction::new(
magic,
module,
governance_action,
target_chain_id,
payload,
)
}
/// Parse an AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation
pub fn parse_authorize_governance_data_source_transfer_payload(encoded_payload: Bytes) -> AuthorizeGovernanceDataSourceTransferPayload {
AuthorizeGovernanceDataSourceTransferPayload {
claim_vaa: encoded_payload,
}
}
pub fn parse_request_governance_data_source_transfer_payload(encoded_payload: Bytes) -> RequestGovernanceDataSourceTransferPayload {
let mut index = 0;
let governance_data_source_index = u32::from_be_bytes([
encoded_payload.get(index).unwrap(),
encoded_payload.get(index + 1).unwrap(),
encoded_payload.get(index + 2).unwrap(),
encoded_payload.get(index + 3).unwrap(),
]);
index += 4;
require(index == encoded_payload.len(), PythError::InvalidGovernanceMessage);
let rdgst = RequestGovernanceDataSourceTransferPayload {
governance_data_source_index,
};
rdgst
}
pub fn parse_set_data_sources_payload(encoded_payload: Bytes) -> SetDataSourcesPayload {
let mut index = 0;
let data_sources_length = encoded_payload.get(index).unwrap().as_u64();
index += 1;
let mut data_sources = Vec::with_capacity(data_sources_length);
let mut i = 0;
while i < data_sources_length {
let (_, slice) = encoded_payload.split_at(index);
let (slice, _) = slice.split_at(2);
let chain_id = u16::from_be_bytes([slice.get(0).unwrap(), slice.get(1).unwrap()]);
index += 2;
let (_, slice) = encoded_payload.split_at(index);
let (slice, _) = slice.split_at(32);
let emitter_address: b256 = slice.into();
index += 32;
data_sources.push(DataSource {
chain_id,
emitter_address,
});
i += 1
}
require(index == encoded_payload.len(), PythError::InvalidGovernanceMessage);
let sds = SetDataSourcesPayload { data_sources };
sds
}
pub fn parse_set_fee_payload(encoded_payload: Bytes) -> SetFeePayload {
let mut index = 0;
let val = u64::from_be_bytes([
encoded_payload.get(index).unwrap(),
encoded_payload.get(index + 1).unwrap(),
encoded_payload.get(index + 2).unwrap(),
encoded_payload.get(index + 3).unwrap(),
encoded_payload.get(index + 4).unwrap(),
encoded_payload.get(index + 5).unwrap(),
encoded_payload.get(index + 6).unwrap(),
encoded_payload.get(index + 7).unwrap(),
]);
index += 8;
let expo = u64::from_be_bytes([
encoded_payload.get(index).unwrap(),
encoded_payload.get(index + 1).unwrap(),
encoded_payload.get(index + 2).unwrap(),
encoded_payload.get(index + 3).unwrap(),
encoded_payload.get(index + 4).unwrap(),
encoded_payload.get(index + 5).unwrap(),
encoded_payload.get(index + 6).unwrap(),
encoded_payload.get(index + 7).unwrap(),
]);
index += 8;
require(encoded_payload.len() == index, PythError::InvalidGovernanceMessage);
let sf = SetFeePayload {
new_fee: val * 10u64.pow(expo.try_as_u32().unwrap()),
};
sf
}
pub fn parse_set_valid_period_payload(encoded_payload: Bytes) -> SetValidPeriodPayload {
let mut index = 0;
let valid_time_period_seconds = u64::from_be_bytes([
encoded_payload.get(index).unwrap(),
encoded_payload.get(index + 1).unwrap(),
encoded_payload.get(index + 2).unwrap(),
encoded_payload.get(index + 3).unwrap(),
encoded_payload.get(index + 4).unwrap(),
encoded_payload.get(index + 5).unwrap(),
encoded_payload.get(index + 6).unwrap(),
encoded_payload.get(index + 7).unwrap(),
]);
index += 8;
require(index == encoded_payload.len(), PythError::InvalidGovernanceMessage);
let svp = SetValidPeriodPayload {
new_valid_period: valid_time_period_seconds,
};
svp
}
}

View File

@ -6,7 +6,6 @@ use pyth_interface::data_structures::{
data_source::DataSource,
wormhole_light::{
GuardianSet,
WormholeProvider,
},
};
use std::{
@ -145,15 +144,6 @@ impl GuardianSetUpgrade {
}
}
impl WormholeProvider {
pub fn new(governance_chain_id: u16, governance_contract: b256) -> Self {
WormholeProvider {
governance_chain_id,
governance_contract,
}
}
}
pub struct GuardianSignature {
guardian_index: u8,
r: b256,
@ -582,7 +572,7 @@ impl WormholeVM {
);
require(
DataSource::new(vm.emitter_chain_id, vm.emitter_address)
.is_valid(is_valid_data_source),
.is_valid_data_source(is_valid_data_source),
WormholeError::InvalidUpdateDataSource,
);
vm

View File

@ -9,6 +9,11 @@ pub enum PythError {
InvalidAttestationSize: (),
InvalidDataSourcesLength: (),
InvalidExponent: (),
InvalidGovernanceDataSource: (),
InvalidGovernanceAction: (),
InvalidGovernanceMessage: (),
InvalidGovernanceModule: (),
InvalidGovernanceTarget: (),
InvalidHeaderSize: (),
InvalidMagic: (),
InvalidMajorVersion: (),
@ -21,9 +26,11 @@ pub enum PythError {
InvalidUpdateDataLength: (),
InvalidUpdateDataSource: (),
InvalidUpgradeModule: (),
InvalidWormholeAddressToSet: (),
LengthOfPriceFeedIdsAndPublishTimesMustMatch: (),
NewGuardianSetIsEmpty: (),
NumberOfUpdatesIrretrievable: (),
OldGovernanceMessage: (),
/// Emitted when a Price's `publish_time` is stale.
OutdatedPrice: (),
/// Emitted when a PriceFeed could not be retrieved.

View File

@ -3,7 +3,6 @@ library;
use pyth_interface::data_structures::{
data_source::DataSource,
price::PriceFeedId,
wormhole_light::WormholeProvider,
};
pub struct ConstructedEvent {
@ -19,3 +18,29 @@ pub struct NewGuardianSetEvent {
pub struct UpdatedPriceFeedsEvent {
updated_price_feeds: Vec<PriceFeedId>,
}
pub struct ContractUpgradedEvent {
old_implementation: Identity,
new_implementation: Identity,
}
pub struct GovernanceDataSourceSetEvent {
old_data_source: DataSource,
new_data_source: DataSource,
initial_sequence: u64,
}
pub struct DataSourcesSetEvent {
old_data_sources: Vec<DataSource>,
new_data_sources: Vec<DataSource>,
}
pub struct FeeSetEvent {
old_fee: u64,
new_fee: u64,
}
pub struct ValidPeriodSetEvent {
old_valid_period: u64,
new_valid_period: u64,
}

View File

@ -15,12 +15,17 @@ use std::{
ZERO_B256,
},
context::msg_amount,
hash::Hash,
hash::{
Hash,
keccak256,
sha256,
},
storage::{
storage_map::StorageMap,
storage_vec::*,
},
u256::U256,
revert::revert,
};
use ::errors::{PythError, WormholeError};
@ -31,8 +36,9 @@ use ::data_structures::{
price::*,
update_type::UpdateType,
wormhole_light::*,
governance_instruction::*,
};
use ::events::{ConstructedEvent, NewGuardianSetEvent, UpdatedPriceFeedsEvent};
use ::events::{ConstructedEvent, NewGuardianSetEvent, UpdatedPriceFeedsEvent, ContractUpgradedEvent, GovernanceDataSourceSetEvent, DataSourcesSetEvent, FeeSetEvent, ValidPeriodSetEvent};
use pyth_interface::{
data_structures::{
@ -42,10 +48,11 @@ use pyth_interface::{
PriceFeed,
PriceFeedId,
},
governance_payload::{UpgradeContractPayload, AuthorizeGovernanceDataSourceTransferPayload, SetDataSourcesPayload, SetFeePayload, SetValidPeriodPayload},
wormhole_light::{
GuardianSet,
WormholeProvider,
},
governance_instruction::{GovernanceInstruction, GovernanceModule, GovernanceAction},
},
PythCore,
PythInfo,
@ -70,6 +77,7 @@ storage {
// Mapping of cached price information
// priceId => PriceInfo
latest_price_feed: StorageMap<PriceFeedId, PriceFeed> = StorageMap {},
// Fee required for each update
single_update_fee: u64 = 0,
// For tracking all active emitter/chain ID pairs
valid_data_sources: StorageVec<DataSource> = StorageVec {},
@ -77,20 +85,38 @@ storage {
/// This includes attestation delay, block time, and potential clock drift
/// between the source/target chains.
valid_time_period_seconds: u64 = 0,
// | |
// --+-- WORMHOLE STATE --+--
// | |
// Mapping of consumed governance actions
wormhole_consumed_governance_actions: StorageMap<b256, bool> = StorageMap {},
// Mapping of guardian_set_index => guardian set
wormhole_guardian_sets: StorageMap<u32, StorageGuardianSet> = StorageMap {},
// Current active guardian set index
wormhole_guardian_set_index: u32 = 0,
// Using Ethereum's Wormhole governance
wormhole_provider: WormholeProvider = WormholeProvider {
governance_chain_id: 0u16,
governance_contract: ZERO_B256,
/// Governance data source. VAA messages from this source can change this contract
/// state. e.g., upgrade the contract, change the valid data sources, and more.
governance_data_source: DataSource = DataSource {
chain_id: 0u16,
emitter_address: ZERO_B256,
},
/// Index of the governance data source, increased each time the governance data source changes.
governance_data_source_index: u32 = 0,
/// Sequence number of the last executed governance message. Any governance message
/// with a lower or equal sequence number will be discarded. This prevents double-execution,
/// and also makes sure that messages are executed in the right order.
last_executed_governance_sequence: u64 = 0,
/// Chain ID of the contract
chain_id: u16 = 0,
/// | |
/// --+-- WORMHOLE STATE --+--
/// | |
/// Mapping of consumed governance actions
wormhole_consumed_governance_actions: StorageMap<b256, bool> = StorageMap {},
/// Mapping of guardian_set_index => guardian set
wormhole_guardian_sets: StorageMap<u32, StorageGuardianSet> = StorageMap {},
/// Current active guardian set index
wormhole_guardian_set_index: u32 = 0,
/// Using Ethereum's Wormhole governance
wormhole_governance_data_source: DataSource = DataSource {
chain_id: 0u16,
emitter_address: ZERO_B256,
},
/// | |
/// --+-- GOVERNANCE STATE --+--
/// | |
current_implementation: Identity = Identity::Address(Address::from(ZERO_B256)),
}
impl SRC5 for Contract {
@ -409,15 +435,61 @@ fn valid_time_period() -> u64 {
storage.valid_time_period_seconds.read()
}
#[storage(read)]
fn governance_data_source() -> DataSource {
storage.governance_data_source.read()
}
#[storage(write)]
fn set_governance_data_source(data_source: DataSource) {
storage.governance_data_source.write(data_source);
}
#[storage(read)]
fn governance_data_source_index() -> u32 {
storage.governance_data_source_index.read()
}
#[storage(write)]
fn set_governance_data_source_index(index: u32) {
storage.governance_data_source_index.write(index);
}
#[storage(read)]
fn last_executed_governance_sequence() -> u64 {
storage.last_executed_governance_sequence.read()
}
#[storage(write)]
fn set_last_executed_governance_sequence(sequence: u64) {
storage.last_executed_governance_sequence.write(sequence);
}
#[storage(read)]
fn chain_id() -> u16 {
storage.chain_id.read()
}
#[storage(read)]
fn current_implementation() -> Identity {
storage.current_implementation.read()
}
impl PythInit for Contract {
#[storage(read, write)]
fn constructor(
data_sources: Vec<DataSource>,
governance_data_source: DataSource,
wormhole_governance_data_source: DataSource,
single_update_fee: u64,
valid_time_period_seconds: u64,
wormhole_guardian_set_upgrade: Bytes,
wormhole_guardian_set_addresses: Vec<b256>,
wormhole_guardian_set_index: u32,
chain_id: u16,
) {
// This function sets the passed identity as the initial owner. https://github.com/FuelLabs/sway-libs/blob/8045a19e3297599750abdf6300c11e9927a29d40/libs/src/ownership.sw#L127-L138
initialize_ownership(DEPLOYER);
// This function ensures that the sender is the owner. https://github.com/FuelLabs/sway-libs/blob/8045a19e3297599750abdf6300c11e9927a29d40/libs/src/ownership.sw#L59-L65
only_owner();
require(data_sources.len > 0, PythError::InvalidDataSourcesLength);
@ -436,26 +508,35 @@ impl PythInit for Contract {
.write(valid_time_period_seconds);
storage.single_update_fee.write(single_update_fee);
let vm = WormholeVM::parse_initial_wormhole_vm(wormhole_guardian_set_upgrade);
let upgrade = GuardianSetUpgrade::parse_encoded_upgrade(0, vm.payload);
let guardian_length: u8 = wormhole_guardian_set_addresses.len().try_as_u8().unwrap();
let mut new_guardian_set = StorageGuardianSet::new(
0,
StorageKey {
slot: sha256(("guardian_set_keys", wormhole_guardian_set_index)),
offset: 0,
field_id: ZERO_B256,
},
);
let mut i: u8 = 0;
while i < guardian_length {
let key: b256 = wormhole_guardian_set_addresses.get(i.as_u64()).unwrap();
new_guardian_set.keys.push(key);
i += 1;
}
storage
.wormhole_consumed_governance_actions
.insert(vm.governance_action_hash, true);
storage
.wormhole_guardian_sets
.insert(upgrade.new_guardian_set_index, upgrade.new_guardian_set);
storage
.wormhole_guardian_set_index
.write(upgrade.new_guardian_set_index);
storage
.wormhole_provider
.write(WormholeProvider::new(vm.emitter_chain_id, vm.emitter_address));
storage.wormhole_guardian_set_index.write(wormhole_guardian_set_index);
storage.wormhole_guardian_sets.insert(wormhole_guardian_set_index, new_guardian_set);
storage.governance_data_source.write(governance_data_source);
storage.wormhole_governance_data_source.write(wormhole_governance_data_source);
storage.chain_id.write(chain_id);
// This function revokes ownership of the current owner and disallows any new owners. https://github.com/FuelLabs/sway-libs/blob/8045a19e3297599750abdf6300c11e9927a29d40/libs/src/ownership.sw#L89-L99
renounce_ownership();
log(ConstructedEvent {
guardian_set_index: upgrade.new_guardian_set_index,
guardian_set_index: wormhole_guardian_set_index,
})
}
}
@ -492,8 +573,8 @@ impl PythInfo for Contract {
}
#[storage(read)]
fn valid_data_source(data_source: DataSource) -> bool {
data_source.is_valid(storage.is_valid_data_source)
fn is_valid_data_source(data_source: DataSource) -> bool {
data_source.is_valid_data_source(storage.is_valid_data_source)
}
}
@ -513,7 +594,7 @@ impl WormholeGuardians for Contract {
}
#[storage(read)]
fn current_wormhole_provider() -> WormholeProvider {
fn current_wormhole_provider() -> DataSource {
current_wormhole_provider()
}
@ -546,8 +627,8 @@ fn current_guardian_set_index() -> u32 {
}
#[storage(read)]
fn current_wormhole_provider() -> WormholeProvider {
storage.wormhole_provider.read()
fn current_wormhole_provider() -> DataSource {
storage.wormhole_governance_data_source.read()
}
#[storage(read)]
@ -573,12 +654,12 @@ fn submit_new_guardian_set(encoded_vm: Bytes) {
let current_wormhole_provider = current_wormhole_provider();
require(
vm.emitter_chain_id == current_wormhole_provider
.governance_chain_id,
.chain_id,
WormholeError::InvalidGovernanceChain,
);
require(
vm.emitter_address == current_wormhole_provider
.governance_contract,
.emitter_address,
WormholeError::InvalidGovernanceContract,
);
require(
@ -615,3 +696,194 @@ fn submit_new_guardian_set(encoded_vm: Bytes) {
new_guardian_set_index: upgrade.new_guardian_set_index,
})
}
/// Transfer the governance data source to a new value with sanity checks to ensure the new governance data source can manage the contract.
#[storage(read, write)]
fn authorize_governance_data_source_transfer(payload: AuthorizeGovernanceDataSourceTransferPayload) {
let old_governance_data_source = governance_data_source();
// Parse and verify the VAA contained in the payload to ensure it's valid and can manage the contract
let vm = WormholeVM::parse_and_verify_wormhole_vm(
current_guardian_set_index(),
payload.claim_vaa,
storage.wormhole_guardian_sets,
);
let gi = GovernanceInstruction::parse_governance_instruction(vm.payload);
require(gi.target_chain_id == chain_id() || gi.target_chain_id == 0, PythError::InvalidGovernanceTarget);
require(match gi.action {
GovernanceAction::RequestGovernanceDataSourceTransfer => true,
_ => false,
}, PythError::InvalidGovernanceMessage);
let claim_payload = GovernanceInstruction::parse_request_governance_data_source_transfer_payload(gi.payload);
require(governance_data_source_index() < claim_payload.governance_data_source_index, PythError::OldGovernanceMessage);
set_governance_data_source_index(claim_payload.governance_data_source_index);
let new_governance_data_source = DataSource {
chain_id: vm.emitter_chain_id,
emitter_address: vm.emitter_address,
};
set_governance_data_source(new_governance_data_source);
// Setting the last executed governance to the claimVaa sequence to avoid using older sequences.
set_last_executed_governance_sequence(vm.sequence);
log(GovernanceDataSourceSetEvent {
old_data_source: old_governance_data_source,
new_data_source: new_governance_data_source,
initial_sequence: vm.sequence,
});
}
#[storage(read, write)]
fn set_data_sources(payload: SetDataSourcesPayload) {
let old_data_sources = storage.valid_data_sources.load_vec();
let mut i = 0;
while i < old_data_sources.len {
let data_source = old_data_sources.get(i).unwrap();
storage.is_valid_data_source.insert(data_source, false);
i += 1;
}
// Clear the current list of valid data sources
storage.valid_data_sources.clear();
i = 0;
// Add new data sources from the payload and mark them as valid
while i < payload.data_sources.len {
let data_source = payload.data_sources.get(i).unwrap();
storage.valid_data_sources.push(data_source);
storage.is_valid_data_source.insert(data_source, true);
i += 1;
}
// Emit an event with the old and new data sources
log(DataSourcesSetEvent {
old_data_sources: old_data_sources,
new_data_sources: storage.valid_data_sources.load_vec(),
});
}
#[storage(read, write)]
fn set_fee(payload: SetFeePayload) {
let old_fee = storage.single_update_fee.read();
storage.single_update_fee.write(payload.new_fee);
log(FeeSetEvent {
old_fee,
new_fee: payload.new_fee,
});
}
#[storage(read, write)]
fn set_valid_period(payload: SetValidPeriodPayload) {
let old_valid_period = storage.valid_time_period_seconds.read();
storage.valid_time_period_seconds.write(payload.new_valid_period);
log(ValidPeriodSetEvent {
old_valid_period,
new_valid_period: payload.new_valid_period,
});
}
abi PythGovernance {
#[storage(read)]
fn governance_data_source() -> DataSource;
#[storage(read, write)]
fn execute_governance_instruction(encoded_vm: Bytes);
}
impl PythGovernance for Contract {
#[storage(read)]
fn governance_data_source() -> DataSource {
governance_data_source()
}
#[storage(read, write)]
fn execute_governance_instruction(encoded_vm: Bytes) {
let vm = verify_governance_vm(encoded_vm);
// Log so that the WormholeVM struct will show up in the ABI and can be used in the tests
log(vm);
let gi = GovernanceInstruction::parse_governance_instruction(vm.payload);
// Log so that the GovernanceInstruction struct will show up in the ABI and can be used in the tests
log(gi);
require(gi.target_chain_id == chain_id() || gi.target_chain_id == 0, PythError::InvalidGovernanceTarget);
match gi.action {
GovernanceAction::UpgradeContract => {
require(gi.target_chain_id != 0, PythError::InvalidGovernanceTarget);
// TODO: implement upgrade_upgradeable_contract(uc) when Fuel releases the upgrade standard library;
log("Upgrade functionality not implemented");
revert(0u64);
},
GovernanceAction::AuthorizeGovernanceDataSourceTransfer => {
let agdst = GovernanceInstruction::parse_authorize_governance_data_source_transfer_payload(gi.payload);
log(agdst);
authorize_governance_data_source_transfer(agdst);
},
GovernanceAction::SetDataSources => {
let sdsp = GovernanceInstruction::parse_set_data_sources_payload(gi.payload);
log(sdsp);
set_data_sources(sdsp);
},
GovernanceAction::SetFee => {
let sf = GovernanceInstruction::parse_set_fee_payload(gi.payload);
log(sf);
set_fee(sf);
},
GovernanceAction::SetValidPeriod => {
let svp = GovernanceInstruction::parse_set_valid_period_payload(gi.payload);
log(svp);
set_valid_period(svp);
},
GovernanceAction::RequestGovernanceDataSourceTransfer => {
// RequestGovernanceDataSourceTransfer can be only part of AuthorizeGovernanceDataSourceTransfer message
// The `revert` function only accepts u64, so as
// a workaround we use require.
require(false, PythError::InvalidGovernanceMessage);
},
_ => {
// The `revert` function only accepts u64, so as
// a workaround we use require.
require(false, PythError::InvalidGovernanceMessage);
}
}
}
}
#[storage(read, write)]
fn verify_governance_vm(encoded_vm: Bytes) -> WormholeVM {
let vm = WormholeVM::parse_and_verify_wormhole_vm(
current_guardian_set_index(),
encoded_vm,
storage
.wormhole_guardian_sets,
);
require(
storage
.governance_data_source
.read()
.is_valid_governance_data_source(vm.emitter_chain_id, vm.emitter_address),
PythError::InvalidGovernanceDataSource,
);
require(
vm.sequence > last_executed_governance_sequence(),
PythError::OldGovernanceMessage,
);
set_last_executed_governance_sequence(vm.sequence);
vm
}

View File

@ -2,4 +2,6 @@ library;
pub mod data_source;
pub mod price;
pub mod governance_payload;
pub mod governance_instruction;
pub mod wormhole_light;

View File

@ -0,0 +1,29 @@
library;
use std::bytes::Bytes;
pub struct GovernanceInstruction {
magic: u32,
module: GovernanceModule,
action: GovernanceAction,
target_chain_id: u16,
payload: Bytes,
}
pub enum GovernanceModule {
Executor: (), // 0
Target: (), // 1
EvmExecutor: (), // 2
StacksTarget: (), // 3
Invalid: (),
}
pub enum GovernanceAction {
UpgradeContract: (), // 0
AuthorizeGovernanceDataSourceTransfer: (), // 1
SetDataSources: (), // 2
SetFee: (), // 3
SetValidPeriod: (), // 4
RequestGovernanceDataSourceTransfer: (), // 5
Invalid: (),
}

View File

@ -0,0 +1,29 @@
library;
use std::bytes::Bytes;
use ::data_structures::data_source::DataSource;
pub struct UpgradeContractPayload {
new_implementation: Identity,
}
pub struct AuthorizeGovernanceDataSourceTransferPayload {
claim_vaa: Bytes,
}
pub struct RequestGovernanceDataSourceTransferPayload {
governance_data_source_index: u32,
}
pub struct SetDataSourcesPayload {
data_sources: Vec<DataSource>,
}
pub struct SetFeePayload {
new_fee: u64,
}
pub struct SetValidPeriodPayload {
new_valid_period: u64,
}

View File

@ -4,8 +4,3 @@ pub struct GuardianSet {
expiration_time: u64,
keys: Vec<b256>,
}
pub struct WormholeProvider {
governance_chain_id: u16,
governance_contract: b256,
}

View File

@ -9,9 +9,9 @@ use ::data_structures::{
PriceFeed,
PriceFeedId,
},
governance_payload::UpgradeContractPayload,
wormhole_light::{
GuardianSet,
WormholeProvider,
},
};
use std::{bytes::Bytes, storage::storage_vec::*};
@ -259,9 +259,13 @@ abi PythInit {
#[storage(read, write)]
fn constructor(
data_sources: Vec<DataSource>,
governance_data_source: DataSource,
wormhole_governance_data_source: DataSource,
single_update_fee: u64,
valid_time_period_seconds: u64,
wormhole_guardian_set_upgrade: Bytes,
wormhole_guardian_set_addresses: Vec<b256>,
wormhole_guardian_set_index: u32,
chain_id: u16,
);
}
@ -284,7 +288,7 @@ abi PythInfo {
fn single_update_fee() -> u64;
#[storage(read)]
fn valid_data_source(data_source: DataSource) -> bool;
fn is_valid_data_source(data_source: DataSource) -> bool;
#[storage(read)]
fn valid_data_sources() -> Vec<DataSource>;
@ -295,7 +299,7 @@ abi WormholeGuardians {
fn current_guardian_set_index() -> u32;
#[storage(read)]
fn current_wormhole_provider() -> WormholeProvider;
fn current_wormhole_provider() -> DataSource;
#[storage(read)]
fn governance_action_is_consumed(hash: b256) -> bool;

View File

@ -2,13 +2,13 @@ use fuels::{
prelude::{Address, Provider, WalletUnlocked},
types::Bits256,
};
use pyth_sdk::{constants::BETA_5_URL, pyth_utils::guardian_set_upgrade_4_vaa};
use pyth_sdk::{constants::BETA_5_URL, pyth_utils::guardian_set_upgrade_4_addresses};
use pyth_sdk::{
constants::{
BTC_USD_PRICE_FEED_ID, DEFAULT_VALID_TIME_PERIOD, ETH_USD_PRICE_FEED_ID,
BTC_USD_PRICE_FEED_ID, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID, ETH_USD_PRICE_FEED_ID,
USDC_USD_PRICE_FEED_ID,
},
pyth_utils::{update_data_bytes, Pyth},
pyth_utils::{update_data_bytes, DataSource, Pyth},
};
#[tokio::main]
@ -26,8 +26,31 @@ async fn main() {
let pyth = Pyth::deploy(admin).await.unwrap();
let governance_data_source: DataSource = DataSource {
chain_id: 1,
emitter_address: Bits256::from_hex_str(
"5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e",
)
.unwrap(),
};
let wormhole_governance_data_source: DataSource = DataSource {
chain_id: 1,
emitter_address: Bits256([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4,
]),
};
let _ = pyth
.constructor(DEFAULT_VALID_TIME_PERIOD, guardian_set_upgrade_4_vaa())
.constructor(
governance_data_source,
wormhole_governance_data_source,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_4_addresses(),
4,
DUMMY_CHAIN_ID,
)
.await
.unwrap();

View File

@ -1,6 +1,27 @@
use crate::pyth_utils::{Price, PriceFeed};
use crate::pyth_utils::{DataSource, Price, PriceFeed};
use fuels::types::Bits256;
pub const MAGIC: u32 = 0x5054474d;
pub const GOVERNANCE_DATA_SOURCE: DataSource = DataSource {
chain_id: 1,
emitter_address: Bits256([
0x56, 0x35, 0x97, 0x9a, 0x22, 0x1c, 0x34, 0x93, 0x1e, 0x32, 0x62, 0x0b, 0x92, 0x93, 0xa4, 0x63,
0x06, 0x55, 0x55, 0xea, 0x71, 0xfe, 0x97, 0xcd, 0x62, 0x37, 0xad, 0xe8, 0x75, 0xb1, 0x2e, 0x9e
]),
};
// only used for updating guardian set
pub const WORMHOLE_GOVERNANCE_DATA_SOURCE: DataSource = DataSource {
chain_id: 1,
emitter_address: Bits256([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 4,
]),
};
pub const DUMMY_CHAIN_ID: u16 = 1;
pub const BETA_5_URL: &str = "beta-5.fuel.network";
pub const BETA_5_PYTH_CONTRACT_ID: &str =
"0xe69daeb9fcf4c536c0fe402403b4b9e9822cc8b1f296e5d754be12cc384554c5";

View File

@ -16,7 +16,9 @@ use fuels::{
use rand::Rng;
use reqwest;
use serde_json;
use serde_wormhole::RawMessage;
use std::path::PathBuf;
use wormhole_sdk::Vaa;
abigen!(Contract(
name = "PythOracleContract",
@ -87,6 +89,80 @@ pub fn test_accumulator_update_data_bytes() -> Vec<Bytes> {
)]
}
pub fn create_set_fee_payload(new_fee: u64, exponent: u64) -> Vec<u8> {
let base = new_fee / 10u64.pow(exponent.try_into().unwrap());
let base_bytes = base.to_be_bytes();
let exponent_bytes = exponent.to_be_bytes();
let mut payload = Vec::new();
payload.extend_from_slice(&base_bytes);
payload.extend_from_slice(&exponent_bytes);
payload
}
pub fn create_set_valid_period_payload(new_valid_period: u64) -> Vec<u8> {
let valid_period_bytes = new_valid_period.to_be_bytes();
let mut payload = Vec::new();
payload.extend_from_slice(&valid_period_bytes);
payload
}
pub fn create_set_data_sources_payload(data_sources: Vec<DataSource>) -> Vec<u8> {
let mut payload = Vec::new();
payload.push(data_sources.len() as u8);
for data_source in data_sources {
payload.extend_from_slice(&data_source.chain_id.to_be_bytes());
payload.extend_from_slice(&data_source.emitter_address.0);
}
payload
}
pub fn create_authorize_governance_data_source_transfer_payload(
claim_vaa: Vaa<Box<RawMessage>>,
) -> Vec<u8> {
serde_wormhole::to_vec(&claim_vaa).unwrap()
}
pub fn create_request_governance_data_source_transfer_payload(
governance_data_source_index: u32,
) -> Vec<u8> {
let index_bytes = governance_data_source_index.to_be_bytes();
let mut payload = Vec::new();
payload.extend_from_slice(&index_bytes);
payload
}
pub fn create_governance_instruction_payload(
magic: u32,
module: GovernanceModule,
action: GovernanceAction,
target_chain_id: u16,
payload: Vec<u8>,
) -> Vec<u8> {
let mut buffer = Vec::new();
buffer.extend_from_slice(&magic.to_be_bytes());
let module_number = match module {
GovernanceModule::Executor => 0,
GovernanceModule::Target => 1,
GovernanceModule::EvmExecutor => 2,
GovernanceModule::StacksTarget => 3,
GovernanceModule::Invalid => u8::MAX, // Typically 255 for invalid
};
buffer.push(module_number);
let action_number = match action {
GovernanceAction::UpgradeContract => 0,
GovernanceAction::AuthorizeGovernanceDataSourceTransfer => 1,
GovernanceAction::SetDataSources => 2,
GovernanceAction::SetFee => 3,
GovernanceAction::SetValidPeriod => 4,
GovernanceAction::RequestGovernanceDataSourceTransfer => 5,
GovernanceAction::Invalid => u8::MAX, // Typically 255 for invalid
};
buffer.push(action_number);
buffer.extend_from_slice(&target_chain_id.to_be_bytes());
buffer.extend_from_slice(&payload);
buffer
}
impl Pyth {
pub async fn price(&self, price_feed_id: Bits256) -> Result<FuelCallResponse<Price>, Error> {
self.instance
@ -119,16 +195,24 @@ impl Pyth {
pub async fn constructor(
&self,
governance_data_source: DataSource,
wormhole_governance_data_source: DataSource,
valid_time_period_seconds: u64,
wormhole_guardian_set_upgrade: Bytes,
wormhole_guardian_set_addresses: Vec<Bits256>,
wormhole_guardian_set_index: u32,
chain_id: u16,
) -> Result<FuelCallResponse<()>, Error> {
self.instance
.methods()
.constructor(
default_data_sources(),
governance_data_source,
wormhole_governance_data_source,
DEFAULT_SINGLE_UPDATE_FEE,
valid_time_period_seconds,
wormhole_guardian_set_upgrade,
wormhole_guardian_set_addresses,
wormhole_guardian_set_index,
chain_id,
)
.with_tx_policies(TxPolicies::default().with_gas_price(1))
.call()
@ -173,6 +257,68 @@ pub fn guardian_set_upgrade_4_vaa() -> Bytes {
Bytes(hex::decode(GUARDIAN_SET_UPGRADE_4_VAA).unwrap())
}
// Full list of guardian set upgrade 3 addresses can be found here: https://github.com/wormhole-foundation/wormhole-networks/blob/master/mainnetv2/guardianset/v3.prototxt
pub fn guardian_set_upgrade_3_addresses() -> Vec<Bits256> {
let addresses = vec![
"58CC3AE5C097b213cE3c81979e1B9f9570746AA5", // Certus One
"fF6CB952589BDE862c25Ef4392132fb9D4A42157", // Staked
"114De8460193bdf3A2fCf81f86a09765F4762fD1", // Figment
"107A0086b32d7A0977926A205131d8731D39cbEB", // ChainodeTech
"8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2", // Inotel
"11b39756C042441BE6D8650b69b54EbE715E2343", // HashQuark
"54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd", // Chainlayer
"15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20", // xLabs
"74a3bf913953D695260D88BC1aA25A4eeE363ef0", // Forbole
"000aC0076727b35FBea2dAc28fEE5cCB0fEA768e", // Staking Fund
"AF45Ced136b9D9e24903464AE889F5C8a723FC14", // Moonlet Wallet
"f93124b7c738843CBB89E864c862c38cddCccF95", // P2P
"D2CC37A4dc036a8D232b48f62cDD4731412f4890", // 01Node
"DA798F6896A3331F64b48c12D1D57Fd9cbe70811", // MCF
"71AA1BE1D36CaFE3867910F99C09e347899C19C3", // Everstake
"8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf", // Chorus One
"178e21ad2E77AE06711549CFBB1f9c7a9d8096e8", // Syncnode
"5E1487F35515d02A92753504a8D75471b9f49EdB", // Triton
"6FbEBc898F403E4773E95feB15E80C9A99c8348d", // Staking Facilities
];
// Convert the addresses to Bits256 by padding the leftmost 12 bytes with zeros. This is done because the original 20-byte key is shorter than the 32-byte b256 type.
addresses
.iter()
.map(|&addr| Bits256::from_hex_str(&format!("{:0>64}", addr)).unwrap())
.collect()
}
// Full list of guardian set upgrade 4 addresses can be found here: https://github.com/wormhole-foundation/wormhole-networks/blob/master/mainnetv2/guardianset/v4.prototxt
pub fn guardian_set_upgrade_4_addresses() -> Vec<Bits256> {
let addresses = vec![
"5893B5A76c3f739645648885bDCcC06cd70a3Cd3", // RockawayX
"fF6CB952589BDE862c25Ef4392132fb9D4A42157", // Staked
"114De8460193bdf3A2fCf81f86a09765F4762fD1", // Figment
"107A0086b32d7A0977926A205131d8731D39cbEB", // ChainodeTech
"8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2", // Inotel
"11b39756C042441BE6D8650b69b54EbE715E2343", // HashQuark
"54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd", // Chainlayer
"15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20", // xLabs
"74a3bf913953D695260D88BC1aA25A4eeE363ef0", // Forbole
"000aC0076727b35FBea2dAc28fEE5cCB0fEA768e", // Staking Fund
"AF45Ced136b9D9e24903464AE889F5C8a723FC14", // Moonlet Wallet
"f93124b7c738843CBB89E864c862c38cddCccF95", // P2P
"D2CC37A4dc036a8D232b48f62cDD4731412f4890", // 01Node
"DA798F6896A3331F64b48c12D1D57Fd9cbe70811", // MCF
"71AA1BE1D36CaFE3867910F99C09e347899C19C3", // Everstake
"8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf", // Chorus One
"178e21ad2E77AE06711549CFBB1f9c7a9d8096e8", // Syncnode
"5E1487F35515d02A92753504a8D75471b9f49EdB", // Triton
"6FbEBc898F403E4773E95feB15E80C9A99c8348d", // Staking Facilities
];
// Convert the addresses to Bits256 by padding the leftmost 12 bytes with zeros. This is done because the original 20-byte key is shorter than the 32-byte b256 type.
addresses
.iter()
.map(|&addr| Bits256::from_hex_str(&format!("{:0>64}", addr)).unwrap())
.collect()
}
pub fn default_price_feed_ids() -> Vec<Bits256> {
vec![
Bits256(

View File

@ -1,4 +1,5 @@
pub(crate) mod pyth_core;
pub(crate) mod pyth_info;
pub(crate) mod pyth_init;
pub(crate) mod pyth_governance;
pub(crate) mod wormhole_guardians;

View File

@ -5,12 +5,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
DEFAULT_SINGLE_UPDATE_FEE, DUMMY_CHAIN_ID, GOVERNANCE_DATA_SOURCE,
TEST_ACCUMULATOR_ETH_USD_PRICE_FEED, TEST_ACCUMULATOR_USDC_USD_PRICE_FEED,
TEST_BATCH_ETH_USD_PRICE_FEED, TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +27,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
TEST_EXTENDED_TIME_PERIOD, //As the contract checks against the current timestamp, this allows unit testing with old but real price updates
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -64,9 +69,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
TEST_EXTENDED_TIME_PERIOD, //As the contract checks against the current timestamp, this allows unit testing with old but real price updates
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -4,12 +4,13 @@ use crate::utils::interface::{
};
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +27,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -72,9 +77,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -5,12 +5,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, GOVERNANCE_DATA_SOURCE,
TEST_ACCUMULATOR_ETH_USD_PRICE_FEED, TEST_ACCUMULATOR_USDC_USD_PRICE_FEED,
TEST_BATCH_ETH_USD_PRICE_FEED, TEST_BATCH_USDC_USD_PRICE_FEED,
WORMHOLE_GOVERNANCE_DATA_SOURCE, DUMMY_CHAIN_ID
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +27,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -64,9 +69,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -5,12 +5,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +27,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -59,9 +64,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -2,16 +2,16 @@ use crate::utils::interface::{
pyth_core::{price, update_fee, update_price_feeds},
pyth_init::constructor,
};
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
DEFAULT_SINGLE_UPDATE_FEE, DUMMY_CHAIN_ID, GOVERNANCE_DATA_SOURCE,
TEST_ACCUMULATOR_ETH_USD_PRICE_FEED, TEST_ACCUMULATOR_USDC_USD_PRICE_FEED,
TEST_BATCH_ETH_USD_PRICE_FEED, TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +26,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
TEST_EXTENDED_TIME_PERIOD, //As the contract checks against the current timestamp, this allows unit testing with old but real price updates
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -64,9 +68,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
TEST_EXTENDED_TIME_PERIOD, //As the contract checks against the current timestamp, this allows unit testing with old but real price updates
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -5,12 +5,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD,
TEST_BATCH_USDC_USD_PRICE_FEED, TEST_EXTENDED_TIME_PERIOD, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -27,9 +28,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -73,9 +78,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -5,12 +5,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -25,9 +26,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -63,9 +68,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -1,9 +1,12 @@
use crate::utils::interface::{pyth_core::update_fee, pyth_init::constructor};
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD},
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, guardian_set_upgrade_3_vaa, test_accumulator_update_data_bytes,
default_data_sources, guardian_set_upgrade_3_addresses, test_accumulator_update_data_bytes,
test_batch_update_data_bytes,
},
};
@ -18,9 +21,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -38,9 +45,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -3,12 +3,14 @@ use crate::utils::interface::{
pyth_info::price_feed_exists,
pyth_init::constructor,
};
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD},
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -23,9 +25,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -69,9 +75,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -5,9 +5,12 @@ use crate::utils::interface::{
};
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD},
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -22,9 +25,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -75,9 +82,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -0,0 +1,229 @@
use {
crate::utils::{interface::pyth_init::constructor, setup::setup_environment},
fuels::types::{Bits256, Bytes},
pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::default_data_sources,
},
pythnet_sdk::test_utils::{create_vaa_from_payload, dummy_guardians_addresses},
};
mod success {
use {
super::*,
crate::utils::interface::{
pyth_core::valid_time_period,
pyth_governance::{execute_governance_instruction, governance_data_source},
pyth_info::{single_update_fee, valid_data_sources},
},
pyth_sdk::{
constants::MAGIC,
pyth_utils::{
create_authorize_governance_data_source_transfer_payload,
create_governance_instruction_payload,
create_request_governance_data_source_transfer_payload,
create_set_data_sources_payload, create_set_fee_payload,
create_set_valid_period_payload, DataSource, GovernanceAction, GovernanceModule,
Pyth,
},
},
};
async fn setup_governance_test_environment() -> (Pyth, Vec<Bits256>) {
let (_oracle_contract_id, deployer) = setup_environment().await.unwrap();
let dummy_guardians_addresses: Vec<[u8; 20]> = dummy_guardians_addresses();
let bits256_guardians: Vec<Bits256> = dummy_guardians_addresses
.iter()
.map(|address| {
let mut full_address = [0u8; 32]; // Create a 32-byte array filled with zeros
full_address[12..].copy_from_slice(address); // Copy the 20-byte address into the rightmost part
Bits256(full_address) // Create Bits256 from the 32-byte array
})
.collect();
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
bits256_guardians.clone(),
0,
DUMMY_CHAIN_ID,
)
.await;
(deployer, bits256_guardians)
}
#[tokio::test]
async fn test_set_fee() {
let (deployer, _bits256_guardians) = setup_governance_test_environment().await;
// Test SetFee logic here
let set_fee_payload = create_set_fee_payload(100, 1);
let governance_instruction_payload = create_governance_instruction_payload(
MAGIC,
GovernanceModule::Target,
GovernanceAction::SetFee,
1,
set_fee_payload,
);
let vaa = create_vaa_from_payload(
&governance_instruction_payload,
wormhole_sdk::Address(GOVERNANCE_DATA_SOURCE.emitter_address.0),
wormhole_sdk::Chain::from(GOVERNANCE_DATA_SOURCE.chain_id),
1,
);
execute_governance_instruction(
&deployer.instance,
Bytes(serde_wormhole::to_vec(&vaa).unwrap()),
)
.await;
let fee = single_update_fee(&deployer.instance).await.value;
assert_eq!(fee, 100);
}
#[tokio::test]
async fn test_set_valid_period() {
let (deployer, _bits256_guardians) = setup_governance_test_environment().await;
// Test SetValidPeriod logic here
let set_valid_period_payload = create_set_valid_period_payload(100);
let governance_instruction_payload = create_governance_instruction_payload(
MAGIC,
GovernanceModule::Target,
GovernanceAction::SetValidPeriod,
1,
set_valid_period_payload,
);
let vaa = create_vaa_from_payload(
&governance_instruction_payload,
wormhole_sdk::Address(GOVERNANCE_DATA_SOURCE.emitter_address.0),
wormhole_sdk::Chain::from(GOVERNANCE_DATA_SOURCE.chain_id),
2,
);
execute_governance_instruction(
&deployer.instance,
Bytes(serde_wormhole::to_vec(&vaa).unwrap()),
)
.await;
let valid_period = valid_time_period(&deployer.instance).await.value;
assert_eq!(valid_period, 100);
}
#[tokio::test]
async fn test_set_data_sources() {
let (deployer, _bits256_guardians) = setup_governance_test_environment().await;
// Test SetDataSources
let test_data_sources = vec![
DataSource {
chain_id: 2,
emitter_address: Bits256([1u8; 32]),
},
DataSource {
chain_id: 27,
emitter_address: Bits256([2u8; 32]),
},
];
let set_data_sources_payload = create_set_data_sources_payload(test_data_sources.clone());
let governance_instruction_payload = create_governance_instruction_payload(
MAGIC,
GovernanceModule::Target,
GovernanceAction::SetDataSources,
1,
set_data_sources_payload,
);
let vaa = create_vaa_from_payload(
&governance_instruction_payload,
wormhole_sdk::Address(GOVERNANCE_DATA_SOURCE.emitter_address.0),
wormhole_sdk::Chain::from(GOVERNANCE_DATA_SOURCE.chain_id),
3,
);
execute_governance_instruction(
&deployer.instance,
Bytes(serde_wormhole::to_vec(&vaa).unwrap()),
)
.await;
let new_data_sources = valid_data_sources(&deployer.instance).await.value;
assert_eq!(new_data_sources, test_data_sources);
}
#[tokio::test]
async fn test_authorize_governance_data_source_transfer() {
let (deployer, _bits256_guardians) = setup_governance_test_environment().await;
// Test AuthorizeGovernanceDataSourceTransfer
let new_emitter_address = Bits256([3u8; 32]);
let new_emitter_chain = 2;
// Simulate creating a RequestGovernanceDataSourceTransfer VAA
let request_governance_data_source_transfer_payload =
create_request_governance_data_source_transfer_payload(1);
let mut governance_instruction_payload = create_governance_instruction_payload(
MAGIC,
GovernanceModule::Target,
GovernanceAction::RequestGovernanceDataSourceTransfer,
1,
request_governance_data_source_transfer_payload,
);
let mut vaa = create_vaa_from_payload(
&governance_instruction_payload,
wormhole_sdk::Address(new_emitter_address.0),
wormhole_sdk::Chain::from(new_emitter_chain),
4,
);
// Authorize the transfer
let authorize_governance_data_source_transfer_payload =
create_authorize_governance_data_source_transfer_payload(vaa);
governance_instruction_payload = create_governance_instruction_payload(
MAGIC,
GovernanceModule::Target,
GovernanceAction::AuthorizeGovernanceDataSourceTransfer,
1,
authorize_governance_data_source_transfer_payload,
);
vaa = create_vaa_from_payload(
&governance_instruction_payload,
wormhole_sdk::Address(GOVERNANCE_DATA_SOURCE.emitter_address.0),
wormhole_sdk::Chain::from(GOVERNANCE_DATA_SOURCE.chain_id),
5,
);
let old_governance_data_source = governance_data_source(&deployer.instance).await;
execute_governance_instruction(
&deployer.instance,
Bytes(serde_wormhole::to_vec(&vaa).unwrap()),
)
.await;
let new_governance_data_source = governance_data_source(&deployer.instance).await;
assert_ne!(
old_governance_data_source.value.emitter_address,
new_governance_data_source.value.emitter_address
);
assert_ne!(
old_governance_data_source.value.chain_id,
new_governance_data_source.value.chain_id
);
assert_eq!(
new_governance_data_source.value.emitter_address,
new_emitter_address
);
assert_eq!(new_governance_data_source.value.chain_id, new_emitter_chain);
}
}

View File

@ -0,0 +1 @@
pub(crate) mod execute_governance_instruction;

View File

@ -6,12 +6,13 @@ use crate::utils::interface::{
use crate::utils::setup::setup_environment;
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, DUMMY_CHAIN_ID,
GOVERNANCE_DATA_SOURCE, TEST_ACCUMULATOR_ETH_USD_PRICE_FEED,
TEST_ACCUMULATOR_USDC_USD_PRICE_FEED, TEST_BATCH_ETH_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED,
TEST_BATCH_USDC_USD_PRICE_FEED, WORMHOLE_GOVERNANCE_DATA_SOURCE,
},
pyth_utils::{
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_vaa,
default_data_sources, default_price_feed_ids, guardian_set_upgrade_3_addresses,
test_accumulator_update_data_bytes, test_batch_update_data_bytes,
},
};
@ -26,9 +27,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;
@ -57,9 +62,13 @@ mod success {
constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID,
)
.await;

View File

@ -1,6 +1,6 @@
use crate::utils::interface::{
pyth_core::valid_time_period,
pyth_info::{owner, single_update_fee, valid_data_source, valid_data_sources},
pyth_info::{is_valid_data_source, owner, single_update_fee, valid_data_sources},
pyth_init::constructor,
wormhole_guardians::{
current_guardian_set_index, current_wormhole_provider, governance_action_is_consumed,
@ -8,10 +8,10 @@ use crate::utils::interface::{
};
use pyth_sdk::{
constants::{
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, UPGRADE_3_VAA_GOVERNANCE_ACTION_HASH,
DEFAULT_SINGLE_UPDATE_FEE, DEFAULT_VALID_TIME_PERIOD, UPGRADE_3_VAA_GOVERNANCE_ACTION_HASH, GOVERNANCE_DATA_SOURCE, WORMHOLE_GOVERNANCE_DATA_SOURCE, DUMMY_CHAIN_ID
},
pyth_utils::{
default_data_sources, guardian_set_upgrade_3_vaa, ConstructedEvent, State, WormholeProvider,
default_data_sources, guardian_set_upgrade_3_addresses, ConstructedEvent, DataSource, State,
},
};
@ -29,7 +29,7 @@ mod success {
// Initial values
assert!(
!valid_data_source(&deployer.instance, &default_data_sources()[0])
!is_valid_data_source(&deployer.instance, &default_data_sources()[0])
.await
.value
);
@ -50,9 +50,9 @@ mod success {
);
assert_eq!(
current_wormhole_provider(&deployer.instance,).await.value,
WormholeProvider {
governance_chain_id: 0,
governance_contract: Bits256::zeroed(),
DataSource {
chain_id: 0,
emitter_address: Bits256::zeroed(),
}
);
assert_eq!(owner(&deployer.instance,).await.value, State::Uninitialized);
@ -60,9 +60,13 @@ mod success {
let response = constructor(
&deployer.instance,
default_data_sources(),
GOVERNANCE_DATA_SOURCE,
WORMHOLE_GOVERNANCE_DATA_SOURCE,
DEFAULT_SINGLE_UPDATE_FEE,
DEFAULT_VALID_TIME_PERIOD,
guardian_set_upgrade_3_vaa(),
guardian_set_upgrade_3_addresses(),
3,
DUMMY_CHAIN_ID
)
.await;
@ -79,7 +83,7 @@ mod success {
// Final values
assert!(
valid_data_source(&deployer.instance, &default_data_sources()[0])
is_valid_data_source(&deployer.instance, &default_data_sources()[0])
.await
.value
);
@ -95,20 +99,15 @@ mod success {
single_update_fee(&deployer.instance).await.value,
DEFAULT_SINGLE_UPDATE_FEE
);
assert!(
governance_action_is_consumed(&deployer.instance, UPGRADE_3_VAA_GOVERNANCE_ACTION_HASH)
.await
.value
);
assert_eq!(
current_guardian_set_index(&deployer.instance,).await.value,
3
);
assert_eq!(
current_wormhole_provider(&deployer.instance,).await.value,
WormholeProvider {
governance_chain_id: 1,
governance_contract: Bits256([
DataSource {
chain_id: 1,
emitter_address: Bits256([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 4
])

View File

@ -1 +1 @@
pub(crate) mod constuctor;
pub(crate) mod constructor;

View File

@ -1,4 +1,5 @@
pub(crate) mod pyth_core;
pub(crate) mod pyth_info;
pub(crate) mod pyth_init;
pub(crate) mod pyth_governance;
pub(crate) mod wormhole_guardians;

View File

@ -0,0 +1,27 @@
use fuels::{
accounts::wallet::WalletUnlocked, programs::call_response::FuelCallResponse, types::Bytes,
};
use pyth_sdk::pyth_utils::{DataSource, PythOracleContract};
pub(crate) async fn execute_governance_instruction(
contract: &PythOracleContract<WalletUnlocked>,
encoded_vm: Bytes,
) -> FuelCallResponse<()> {
contract
.methods()
.execute_governance_instruction(encoded_vm)
.call()
.await
.unwrap()
}
pub(crate) async fn governance_data_source(
contract: &PythOracleContract<WalletUnlocked>,
) -> FuelCallResponse<DataSource> {
contract
.methods()
.governance_data_source()
.call()
.await
.unwrap()
}

View File

@ -40,13 +40,13 @@ pub(crate) async fn single_update_fee(
contract.methods().single_update_fee().call().await.unwrap()
}
pub(crate) async fn valid_data_source(
pub(crate) async fn is_valid_data_source(
contract: &PythOracleContract<WalletUnlocked>,
data_source: &DataSource,
) -> FuelCallResponse<bool> {
contract
.methods()
.valid_data_source(data_source.clone())
.is_valid_data_source(data_source.clone())
.call()
.await
.unwrap()

View File

@ -1,5 +1,6 @@
use fuels::{
accounts::wallet::WalletUnlocked, prelude::Bytes, programs::call_response::FuelCallResponse,
accounts::wallet::WalletUnlocked, programs::call_response::FuelCallResponse,
types::Bits256,
};
use pyth_sdk::pyth_utils::{DataSource, PythOracleContract};
@ -7,17 +8,25 @@ use pyth_sdk::pyth_utils::{DataSource, PythOracleContract};
pub(crate) async fn constructor(
contract: &PythOracleContract<WalletUnlocked>,
data_sources: Vec<DataSource>,
governance_data_source: DataSource,
wormhole_governance_data_source: DataSource,
single_update_fee: u64,
valid_time_period_seconds: u64,
wormhole_guardian_set_upgrade: Bytes,
wormhole_guardian_set_addresses: Vec<Bits256>,
wormhole_guardian_set_index: u32,
chain_id: u16,
) -> FuelCallResponse<()> {
contract
.methods()
.constructor(
data_sources,
governance_data_source,
wormhole_governance_data_source,
single_update_fee,
valid_time_period_seconds,
wormhole_guardian_set_upgrade,
wormhole_guardian_set_addresses,
wormhole_guardian_set_index,
chain_id,
)
.call()
.await

View File

@ -1,7 +1,7 @@
use fuels::{
accounts::wallet::WalletUnlocked, programs::call_response::FuelCallResponse, types::Bits256,
};
use pyth_sdk::pyth_utils::{GuardianSet, PythOracleContract, WormholeProvider};
use pyth_sdk::pyth_utils::{GuardianSet, PythOracleContract, DataSource};
pub(crate) async fn current_guardian_set_index(
contract: &PythOracleContract<WalletUnlocked>,
@ -16,7 +16,7 @@ pub(crate) async fn current_guardian_set_index(
pub(crate) async fn current_wormhole_provider(
contract: &PythOracleContract<WalletUnlocked>,
) -> FuelCallResponse<WormholeProvider> {
) -> FuelCallResponse<DataSource> {
contract
.methods()
.current_wormhole_provider()