Compare commits
14 Commits
pyth-price
...
main
Author | SHA1 | Date |
---|---|---|
|
cf7987f4c5 | |
|
6e0bd0569b | |
|
1e1be9dbeb | |
|
d105a7aa86 | |
|
dd9b07b5e4 | |
|
e26c9d1a30 | |
|
9dddd3d1e7 | |
|
77c68c5069 | |
|
bf2c8b5d43 | |
|
3f07c27243 | |
|
42b64ac09f | |
|
55cbe62997 | |
|
94b36c4961 | |
|
ff6b11023c |
|
@ -21,10 +21,10 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Download CLI
|
||||
run: wget https://github.com/aptos-labs/aptos-core/releases/download/aptos-cli-v1.0.4/aptos-cli-1.0.4-Ubuntu-22.04-x86_64.zip
|
||||
run: wget https://github.com/aptos-labs/aptos-core/releases/download/aptos-cli-v3.1.0/aptos-cli-3.1.0-Ubuntu-22.04-x86_64.zip
|
||||
|
||||
- name: Unzip CLI
|
||||
run: unzip aptos-cli-1.0.4-Ubuntu-22.04-x86_64.zip
|
||||
run: unzip aptos-cli-3.1.0-Ubuntu-22.04-x86_64.zip
|
||||
|
||||
- name: Run tests
|
||||
run: ./aptos move test
|
||||
|
|
|
@ -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
|
|
@ -1488,7 +1488,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fortuna"
|
||||
version = "5.2.1"
|
||||
version = "5.2.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "fortuna"
|
||||
version = "5.2.1"
|
||||
version = "5.2.2"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -13,7 +13,10 @@ use {
|
|||
},
|
||||
config::EthereumConfig,
|
||||
},
|
||||
anyhow::Result,
|
||||
anyhow::{
|
||||
anyhow,
|
||||
Result,
|
||||
},
|
||||
ethers::{
|
||||
contract::ContractError,
|
||||
providers::{
|
||||
|
@ -64,10 +67,14 @@ async fn get_latest_safe_block(chain_state: &BlockchainState) -> BlockNumber {
|
|||
.await
|
||||
{
|
||||
Ok(latest_confirmed_block) => {
|
||||
return latest_confirmed_block - chain_state.reveal_delay_blocks
|
||||
tracing::info!(
|
||||
"Fetched latest safe block {}",
|
||||
latest_confirmed_block - chain_state.reveal_delay_blocks
|
||||
);
|
||||
return latest_confirmed_block - chain_state.reveal_delay_blocks;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("error while getting block number. error: {:?}", e);
|
||||
tracing::error!("Error while getting block number. error: {:?}", e);
|
||||
time::sleep(RETRY_INTERVAL).await;
|
||||
}
|
||||
}
|
||||
|
@ -346,10 +353,11 @@ pub async fn watch_blocks_wrapper(
|
|||
tx: mpsc::Sender<BlockRange>,
|
||||
geth_rpc_wss: Option<String>,
|
||||
) {
|
||||
let mut last_safe_block_processed = latest_safe_block;
|
||||
loop {
|
||||
if let Err(e) = watch_blocks(
|
||||
chain_state.clone(),
|
||||
latest_safe_block,
|
||||
&mut last_safe_block_processed,
|
||||
tx.clone(),
|
||||
geth_rpc_wss.clone(),
|
||||
)
|
||||
|
@ -368,12 +376,11 @@ pub async fn watch_blocks_wrapper(
|
|||
/// know about it.
|
||||
pub async fn watch_blocks(
|
||||
chain_state: BlockchainState,
|
||||
latest_safe_block: BlockNumber,
|
||||
last_safe_block_processed: &mut BlockNumber,
|
||||
tx: mpsc::Sender<BlockRange>,
|
||||
geth_rpc_wss: Option<String>,
|
||||
) -> Result<()> {
|
||||
tracing::info!("Watching blocks to handle new events");
|
||||
let mut last_safe_block_processed = latest_safe_block;
|
||||
|
||||
let provider_option = match geth_rpc_wss {
|
||||
Some(wss) => Some(match Provider::<Ws>::connect(wss.clone()).await {
|
||||
|
@ -390,14 +397,23 @@ pub async fn watch_blocks(
|
|||
};
|
||||
|
||||
let mut stream_option = match provider_option {
|
||||
Some(ref provider) => Some(provider.subscribe_blocks().await?),
|
||||
Some(ref provider) => Some(match provider.subscribe_blocks().await {
|
||||
Ok(client) => client,
|
||||
Err(e) => {
|
||||
tracing::error!("Error while subscribing to blocks. error {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
|
||||
loop {
|
||||
match stream_option {
|
||||
Some(ref mut stream) => {
|
||||
stream.next().await;
|
||||
if let None = stream.next().await {
|
||||
tracing::error!("Error blocks subscription stream ended");
|
||||
return Err(anyhow!("Error blocks subscription stream ended"));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
time::sleep(POLL_INTERVAL).await;
|
||||
|
@ -405,27 +421,27 @@ pub async fn watch_blocks(
|
|||
}
|
||||
|
||||
let latest_safe_block = get_latest_safe_block(&chain_state).in_current_span().await;
|
||||
if latest_safe_block > last_safe_block_processed {
|
||||
if latest_safe_block > *last_safe_block_processed {
|
||||
match tx
|
||||
.send(BlockRange {
|
||||
from: last_safe_block_processed + 1,
|
||||
from: *last_safe_block_processed + 1,
|
||||
to: latest_safe_block,
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
tracing::info!(
|
||||
from_block = &last_safe_block_processed + 1,
|
||||
from_block = *last_safe_block_processed + 1,
|
||||
to_block = &latest_safe_block,
|
||||
"Block range sent to handle events",
|
||||
);
|
||||
last_safe_block_processed = latest_safe_block;
|
||||
*last_safe_block_processed = latest_safe_block;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Error while sending block range to handle events. These will be handled in next call. error: {:?}",
|
||||
e
|
||||
);
|
||||
"Error while sending block range to handle events. These will be handled in next call. error: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@pythnetwork/price-pusher",
|
||||
"version": "6.7.1",
|
||||
"version": "6.7.2",
|
||||
"description": "Pyth Price Pusher",
|
||||
"homepage": "https://pyth.network",
|
||||
"main": "lib/index.js",
|
||||
|
|
|
@ -9,6 +9,9 @@ import near from "./near/command";
|
|||
import solana from "./solana/command";
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.parserConfiguration({
|
||||
"parse-numbers": false,
|
||||
})
|
||||
.config("config")
|
||||
.global("config")
|
||||
.command(evm)
|
||||
|
|
|
@ -44,6 +44,13 @@ export default {
|
|||
required: true,
|
||||
default: 30,
|
||||
} as Options,
|
||||
"ignore-gas-objects": {
|
||||
description:
|
||||
"Gas objects to ignore when merging gas objects on startup -- use this for locked objects.",
|
||||
type: "array",
|
||||
required: false,
|
||||
default: [],
|
||||
} as Options,
|
||||
"gas-budget": {
|
||||
description: "Gas budget for each price update",
|
||||
type: "number",
|
||||
|
@ -73,6 +80,7 @@ export default {
|
|||
pythStateId,
|
||||
wormholeStateId,
|
||||
numGasObjects,
|
||||
ignoreGasObjects,
|
||||
gasBudget,
|
||||
accountIndex,
|
||||
} = argv;
|
||||
|
@ -126,7 +134,8 @@ export default {
|
|||
endpoint,
|
||||
keypair,
|
||||
gasBudget,
|
||||
numGasObjects
|
||||
numGasObjects,
|
||||
ignoreGasObjects
|
||||
);
|
||||
|
||||
const controller = new Controller(
|
||||
|
|
|
@ -162,7 +162,8 @@ export class SuiPricePusher implements IPricePusher {
|
|||
endpoint: string,
|
||||
keypair: Ed25519Keypair,
|
||||
gasBudget: number,
|
||||
numGasObjects: number
|
||||
numGasObjects: number,
|
||||
ignoreGasObjects: string[]
|
||||
): Promise<SuiPricePusher> {
|
||||
if (numGasObjects > MAX_NUM_OBJECTS_IN_ARGUMENT) {
|
||||
throw new Error(
|
||||
|
@ -183,7 +184,8 @@ export class SuiPricePusher implements IPricePusher {
|
|||
const gasPool = await SuiPricePusher.initializeGasPool(
|
||||
keypair,
|
||||
provider,
|
||||
numGasObjects
|
||||
numGasObjects,
|
||||
ignoreGasObjects
|
||||
);
|
||||
|
||||
const pythClient = new SuiPythClient(
|
||||
|
@ -318,17 +320,26 @@ export class SuiPricePusher implements IPricePusher {
|
|||
|
||||
// This function will smash all coins owned by the signer into one, and then
|
||||
// split them equally into numGasObjects.
|
||||
// ignoreGasObjects is a list of gas objects that will be ignored during the
|
||||
// merging -- use this to store any locked objects on initialization.
|
||||
private static async initializeGasPool(
|
||||
signer: Ed25519Keypair,
|
||||
provider: SuiClient,
|
||||
numGasObjects: number
|
||||
numGasObjects: number,
|
||||
ignoreGasObjects: string[]
|
||||
): Promise<SuiObjectRef[]> {
|
||||
const signerAddress = await signer.toSuiAddress();
|
||||
|
||||
if (ignoreGasObjects.length > 0) {
|
||||
console.log("Ignoring some gas objects for coin merging:");
|
||||
console.log(ignoreGasObjects);
|
||||
}
|
||||
|
||||
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(
|
||||
signer,
|
||||
provider,
|
||||
signerAddress
|
||||
signerAddress,
|
||||
ignoreGasObjects
|
||||
);
|
||||
const coinResult = await provider.getObject({
|
||||
id: consolidatedCoin.objectId,
|
||||
|
@ -458,7 +469,8 @@ export class SuiPricePusher implements IPricePusher {
|
|||
private static async mergeGasCoinsIntoOne(
|
||||
signer: Ed25519Keypair,
|
||||
provider: SuiClient,
|
||||
owner: SuiAddress
|
||||
owner: SuiAddress,
|
||||
initialLockedAddresses: string[]
|
||||
): Promise<SuiObjectRef> {
|
||||
const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
|
||||
// skip merging if there is only one coin
|
||||
|
@ -472,6 +484,7 @@ export class SuiPricePusher implements IPricePusher {
|
|||
);
|
||||
let finalCoin;
|
||||
const lockedAddresses: Set<string> = new Set();
|
||||
initialLockedAddresses.forEach((value) => lockedAddresses.add(value));
|
||||
for (let i = 0; i < gasCoinsChunks.length; i++) {
|
||||
const mergeTx = new TransactionBlock();
|
||||
let coins = gasCoinsChunks[i];
|
||||
|
@ -497,7 +510,6 @@ export class SuiPricePusher implements IPricePusher {
|
|||
"quorum of validators because of locked objects. Retried a conflicting transaction"
|
||||
)
|
||||
) {
|
||||
/*
|
||||
Object.values((e as any).data).forEach((lockedObjects: any) => {
|
||||
lockedObjects.forEach((lockedObject: [string, number, string]) => {
|
||||
lockedAddresses.add(lockedObject[0]);
|
||||
|
@ -505,7 +517,6 @@ export class SuiPricePusher implements IPricePusher {
|
|||
});
|
||||
// retry merging without the locked coins
|
||||
i--;
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import { toPrivateKey } from "../src";
|
||||
import {
|
||||
DefaultStore,
|
||||
EvmEntropyContract,
|
||||
PrivateKey,
|
||||
toPrivateKey,
|
||||
} from "../src";
|
||||
import {
|
||||
COMMON_DEPLOY_OPTIONS,
|
||||
findEntropyContract,
|
||||
|
@ -12,26 +17,29 @@ const parser = yargs(hideBin(process.argv))
|
|||
.usage(
|
||||
"Requests a random number from an entropy contract and measures the\n" +
|
||||
"latency between request submission and fulfillment by the Fortuna keeper service.\n" +
|
||||
"Usage: $0 --chain-id <chain-id> --private-key <private-key>"
|
||||
"Usage: $0 --private-key <private-key> --chain <chain-id> | --all-chains <testnet|mainnet>"
|
||||
)
|
||||
.options({
|
||||
chain: {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
desc: "test latency for the contract on this chain",
|
||||
conflicts: "all-chains",
|
||||
},
|
||||
"all-chains": {
|
||||
type: "string",
|
||||
conflicts: "chain",
|
||||
choices: ["testnet", "mainnet"],
|
||||
desc: "test latency for all entropy contracts deployed either on mainnet or testnet",
|
||||
},
|
||||
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const argv = await parser.argv;
|
||||
|
||||
const chain = findEvmChain(argv.chain);
|
||||
const contract = findEntropyContract(chain);
|
||||
|
||||
async function testLatency(
|
||||
contract: EvmEntropyContract,
|
||||
privateKey: PrivateKey
|
||||
) {
|
||||
const provider = await contract.getDefaultProvider();
|
||||
const userRandomNumber = contract.generateUserRandomNumber();
|
||||
const privateKey = toPrivateKey(argv.privateKey);
|
||||
const requestResponse = await contract.requestRandomness(
|
||||
userRandomNumber,
|
||||
provider,
|
||||
|
@ -84,4 +92,27 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const argv = await parser.argv;
|
||||
if (!argv.chain && !argv["all-chains"]) {
|
||||
throw new Error("Must specify either --chain or --all-chains");
|
||||
}
|
||||
const privateKey = toPrivateKey(argv.privateKey);
|
||||
if (argv["all-chains"]) {
|
||||
for (const contract of Object.values(DefaultStore.entropy_contracts)) {
|
||||
if (
|
||||
contract.getChain().isMainnet() ===
|
||||
(argv["all-chains"] === "mainnet")
|
||||
) {
|
||||
console.log(`Testing latency for ${contract.getId()}...`);
|
||||
await testLatency(contract, privateKey);
|
||||
}
|
||||
}
|
||||
} else if (argv.chain) {
|
||||
const chain = findEvmChain(argv.chain);
|
||||
const contract = findEntropyContract(chain);
|
||||
await testLatency(contract, privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
},
|
||||
"apps/price_pusher": {
|
||||
"name": "@pythnetwork/price-pusher",
|
||||
"version": "6.7.1",
|
||||
"version": "6.7.2",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@injectivelabs/sdk-ts": "1.10.72",
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ version = "0.0.1"
|
|||
upgrade_policy = "compatible"
|
||||
|
||||
[dependencies]
|
||||
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "2c74a456298fcd520241a562119b6fe30abdaae2" }
|
||||
MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib/", rev = "2c74a456298fcd520241a562119b6fe30abdaae2" }
|
||||
AptosStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-stdlib/", rev = "2c74a456298fcd520241a562119b6fe30abdaae2" }
|
||||
AptosToken = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-token/", rev = "2c74a456298fcd520241a562119b6fe30abdaae2" }
|
||||
Wormhole = { git = "https://github.com/wormhole-foundation/wormhole.git", subdir = "aptos/wormhole", rev = "f29c8c935123f3b3a917ba5dc930ec68737463c7" }
|
||||
Deployer = { git = "https://github.com/wormhole-foundation/wormhole.git", subdir = "aptos/deployer", rev = "f29c8c935123f3b3a917ba5dc930ec68737463c7" }
|
||||
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "6f83bc6d02207298b2dee91133d75538789bf582" }
|
||||
MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib/", rev = "6f83bc6d02207298b2dee91133d75538789bf582" }
|
||||
AptosStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-stdlib/", rev = "6f83bc6d02207298b2dee91133d75538789bf582" }
|
||||
AptosToken = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-token/", rev = "6f83bc6d02207298b2dee91133d75538789bf582" }
|
||||
Wormhole = { git = "https://github.com/wormhole-foundation/wormhole.git", subdir = "aptos/wormhole", rev = "b8676f09a6e4a92bbaecb5f3d59b5e9b778de082" }
|
||||
Deployer = { git = "https://github.com/wormhole-foundation/wormhole.git", subdir = "aptos/deployer", rev = "b8676f09a6e4a92bbaecb5f3d59b5e9b778de082" }
|
||||
|
||||
[addresses]
|
||||
pyth = "_"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/bash
|
||||
aptos node run-local-testnet --with-faucet --force-restart
|
||||
aptos node run-local-testnet --with-faucet --force-restart --bind-to 0.0.0.0
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -6,3 +6,4 @@ pub mod price;
|
|||
pub mod accumulator_update;
|
||||
pub mod batch_attestation_update;
|
||||
pub mod update_type;
|
||||
pub mod governance_instruction;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -2,4 +2,6 @@ library;
|
|||
|
||||
pub mod data_source;
|
||||
pub mod price;
|
||||
pub mod governance_payload;
|
||||
pub mod governance_instruction;
|
||||
pub mod wormhole_light;
|
||||
|
|
|
@ -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: (),
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -4,8 +4,3 @@ pub struct GuardianSet {
|
|||
expiration_time: u64,
|
||||
keys: Vec<b256>,
|
||||
}
|
||||
|
||||
pub struct WormholeProvider {
|
||||
governance_chain_id: u16,
|
||||
governance_contract: b256,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub(crate) mod execute_governance_instruction;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
])
|
|
@ -1 +1 @@
|
|||
pub(crate) mod constuctor;
|
||||
pub(crate) mod constructor;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -30,85 +30,32 @@ fee_contract_address=0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e
|
|||
${sleep}
|
||||
# guardian set #0
|
||||
wormhole_address=$(starkli deploy "${wormhole_hash}" \
|
||||
"${owner}" \
|
||||
1 `# num_guardians` \
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5 \
|
||||
1 `# chain_id` \
|
||||
1 `# governance_chain_id` \
|
||||
4 0 `# governance_contract` \
|
||||
)
|
||||
|
||||
${sleep}
|
||||
# guardian set #1: https://raw.githubusercontent.com/wormhole-foundation/wormhole-networks/master/mainnetv2/guardianset/v1.prototxt
|
||||
starkli invoke "${wormhole_address}" submit_new_guardian_set \
|
||||
1 `# set index` \
|
||||
19 `# num_guardians` \
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5 \
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157 \
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1 \
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB \
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2 \
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343 \
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd \
|
||||
0xeB5F7389Fa26941519f0863349C223b73a6DDEE7 \
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0 \
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e \
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14 \
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95 \
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890 \
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811 \
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3 \
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf \
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8 \
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB \
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d \
|
||||
16 18 1766847064779994277746302277072294871108550301449637470263976489521154979 374953657095152923031303770743522269007103499920836805761143506434463979495 373725794026553362537846905304981854320892126869150736450761801254169477120 4835703278458516786446336 1131377253 3533694129556775410652111826415980944262631656421498398215501759245151417 145493015216602589471695207668173527044214450021182755196032581352392984224 267497573836069714380350521200881787609530659298168186016481773490244091266 443348533394886521835330696538264729103669807313401311199245411889706258110 200303433165499832354845293203843028338419687800279845786613090211434473108 37282816539161742972709083946551920068062204748477644719930149699874385462 111200938271608595261384934914291476246753101189480743698823215749338358345 5785682963869019134199015821749288033381872318410562688180948003975909269 372447340016996751453958019806457886428852701283870538393820846119845147788 33251468085387571623103303511315696691298281336333243761063342581452341650 323161992096034641767541451811925056802673576212351940217752194462561980347 55852237138651071644815135002358067220635692701051811455610533875912981641 190413173566657072516608762222993749133
|
||||
|
||||
${sleep}
|
||||
# guardian set #2: https://raw.githubusercontent.com/wormhole-foundation/wormhole-networks/master/mainnetv2/guardianset/v2.prototxt
|
||||
starkli invoke "${wormhole_address}" submit_new_guardian_set \
|
||||
2 `# set index` \
|
||||
19 `# num_guardians` \
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5 \
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157 \
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1 \
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB \
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2 \
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343 \
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd \
|
||||
0x66B9590e1c41e0B226937bf9217D1d67Fd4E91F5 \
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0 \
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e \
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14 \
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95 \
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890 \
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811 \
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3 \
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf \
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8 \
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB \
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d \
|
||||
2 44 1766847065210651126944505525521222069599854288126726949998063840465138797 39054013088470866893599813322035661048501117089555726788687392536164861911 186918267413056900890218521593203545230034250983266377769400670103688217224 54214750922097681971590495378823998039261772575502204791108963815396679538 248994008232667872698758486001506749115615219491023036208140426934463230397 224235483823871042187452194579994340291351644933258737665365374081962645784 129444929990547403397151941456764812818993218972657847255833740800106200260 318548597134783137700627869311159664823693239605331630210202210299165477657 308852933010951129895011963941866000261904600807292935694851016610643657184 57272874228621364335170723193404742446392708606247574725663969156507973216 268057363923565984687253533797066429881117576606682526627284795527707196557 421894189151847402000239734668088381785344768284464330085711322870200424121 387584417395337067059819722404321580961380603778956902593594676080614899975 443523131755342451570503958659975367050637907361274652611595274647186073286 375107813087591446268414166006799680982485924290770541964399283524664437852 269085314426821465871247165234113878276592898426373369094610290261431112145 394348694527460459816454348661249546781513091938003106009521096332701847735 125670844183465056159554034633959680574572737212268749779705635378223489518 35053869475614771227400345921974210525173525784259894123687028214330135561 57544237843860512274491447149877290860624174166427313971286819807773907946 110681468147560408039747352809294082929396639199393789980441736520638055418 45709869872872997180086402576677640909777820941436708911954532772405320395 339910511168418517917975736269171135752028257685502872671902330279073260362 76482764517489607955778008190826845581092838692650194719207882266659669490 443663869577220861680293443959666949893574779475752540587040489501289361777 231057874919577223790659840464529054850239319545221055959374917590157019925 309066533217885002074480704480667619809952056265738927105682076502747220549 212379788814604791028007106821871908074818251907335322546331543385945316762 165408661499085325620077702639227003047567884011538988728381864749733773312 29852013947978990147012099107546124222651092940097518043136 5874446556610227706402640854088357165514903 314635470832203526600706472223155382046271943513513368538979543914002758100 289993023590817330918274026889451152915026890048318491140264484864242055689 211265316833000774821515110003986084297271807500310630074520699505436206838 314620948986744608212517578488307826224331071350776523303159889004405167502 242768143829057016675085776170635413106817756232919004913342240722183648628 289318220340670045883106021427202666948428587921558828582664470923483208386 254304247593881109676724582609273741670949040469906895867342151706444640548 324707984060675446628128892371664948354047882542253609514703956739624414429 125786084546320950738753348592393927755418642173185609412108154831520915923 192033422676298173731756291271054199566981168481817292625435767748408605264 70237018464728620254434305961956673950089621204502627373468857093940647376 75218391584551901010047495874303520775865073092730040058902770251005073864 13453
|
||||
|
||||
${sleep}
|
||||
# guardian set #3: https://raw.githubusercontent.com/wormhole-foundation/wormhole-networks/master/mainnetv2/guardianset/v3.prototxt
|
||||
starkli invoke "${wormhole_address}" submit_new_guardian_set \
|
||||
3 `# set index` \
|
||||
19 `# num_guardians` \
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5 \
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157 \
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1 \
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB \
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2 \
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343 \
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd \
|
||||
0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20 \
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0 \
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e \
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14 \
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95 \
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890 \
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811 \
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3 \
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf \
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8 \
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB \
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d \
|
||||
2 44 1766847065622031860560134801367788401015571316785630090767859240961980367 408239335069601434456324970231880063141100099721451058487412176729277688481 239499689753305520381601038928513796227317320911002802551444547638809838552 377515301744513788082523380503265415136454305699441419871183462725292421897 293792427782284265052215516935690252661713253004854348809536189867737815900 307592266914902727916633292174670243188255704510048236277225897328900269063 127373290139474278928992577974696343462455769904046193125018730285162391253 391788800785481654990215164673817619378887263909639120513493454202816019863 410413307118599096084169722886408584518140871169074821252461819158667354254 18837648490111595970198935552266546643395427923804444528866768515056419823 29964034682984173558839379357821569529808274426015494950430380078317881569 86017868501532670528023530422115758730056738654625156800662778409971102579 316587967137295297243489759859408971025377360462781809717927347025414193161 412080542369789462767669836400697110505430973769191785499739175360336337147 342817079347905714229318925597762381802367663565411998187223317628701911440 323381353160339090772037140072061985169258958022395380273676898316834639836 199931590715070935127318740956564588449721873695471932311700469202637695100 53310522180389647586576928116330850824055549848985438538201222342553700451 387322343922164253479438966163491855981414317104760621828688810466847848718 81609701542274539489711635515209037026645626576756528749469616228397567798 182108205861564989333892774796475580877981373947799860454217397980367659628 21549663410658134468902761710868642321546772465973442277960059676129502668 189434039785735939400321781125039794740638779195156759980704929066694157130 52255833533187953003213955242027099690232530588872309460610106220279805641 197105018621162723372171195601447549272902142615124680111298974553437412361 243585516151555343004264928593678764289083751554802049062044286334698216184 98577806073901898829375415748245478967425496216912736575886605480181121443 92916551389967933235240931764170084503123511470557201449603712010638670912 279247190794260779926452059689914005511524938154821508635388069101252378624 27765181507524306000048567556593270127801507143251178553344 5874446556610227706402640926145951203442839 314635470832203526600706472223155382046271943513513368538979543914002758100 289993023590817330918274026889451152915026890048318491140264484864242055689 211265316833000774821515110003986084297271807500310630074520699505436206838 314620948986744608212517578488307826224331071350776523303159889004405167502 242768143829057016675085658054156069029173843566452718977789980910319968372 289318220340670045883106021427202666948428587921558828582664470923483208386 254304247593881109676724582609273741670949040469906895867342151706444640548 324707984060675446628128892371664948354047882542253609514703956739624414429 125786084546320950738753348592393927755418642173185609412108154831520915923 192033422676298173731756291271054199566981168481817292625435767748408605264 70237018464728620254434305961956673950089621204502627373468857093940647376 75218391584551901010047495874303520775865073092730040058902770251005073864 13453
|
||||
|
||||
${sleep}
|
||||
# guardian set #4
|
||||
starkli invoke "${wormhole_address}" submit_new_guardian_set \
|
||||
2 44 1766847066033426987337757245669159273063358729535478806850006662056807068 191023158244075433218055661747029015323596061316379687901032561397223546211 30156550775609732785124128084945604136341937408029517653427049258063209215 301841618969457377999846355946508544313297803407604349411042057045510372286 399879387152070823070522891203531321261797829310211644637928969034931151834 1184971666775858810527395126763859219514013163556756790208661779020321698 427827873217506136303198988655697899138087317492051993053159867826892618987 55439109913191967501571602277685262841453050617358377329061538069328212552 34944602254693785869427132065664922748183924456022812505745784482260734500 50091615215549712387991200985741575718080363004681463525186508796585379155 265247833149227842278059484961926330281584344437952973839486092319885300192 421631446041795295328070636491346018953171276542115189082171457479754499396 59057903625576869235407103565877017330396402246452653660114888284545941770 315797852826246435174946736461540321579373154656484006452063031513301027405 9521420622979958910372839981791309896262328383324674284772682980734269170 272964069264268937653695089515793248726920319914036642027008415285406913245 194708434228888226032102758315234166672190899487218971410889219134701358728 117864954129109327302856065706421701676973859697066630532570005860486924893 323457021720552374478769194145226061243431674370101604382965685057422991463 327482733702858147057975319784026874245182397914737119038454598086198587150 159726033816658034104416471293601013976445904149240898589368461412472508473 165970343982649234398221341351816767302457220504375238905210573566962780340 66269488760319836583658182431744051236825244016843316092957806563966254500 360882001282595740056823749884962228392082962172369522212117195988772429063 202692667772209236945884489592750537635169234501360011152939202347962132650 407257364829649465305126488148712878739144584682351279109461295389594525334 270499607712829989691415988895838806019492861138165540862008308077962735002 388443296961168536186587069708212659389994895697827691755155284015603161464 45068266527940236008536134081672474027695203549460934893262212861351952384 31319268777966350508118557206583844424308993254125039779840 5874446556610227706402640998203302487747647 204224545225244051821590480758420624947979343122083461045877549162059250132 289993023590817330918274026889451152915026890048318491140264484864242055689 211265316833000774821515110003986084297271807500310630074520699505436206838 314620948986744608212517578488307826224331071350776523303159889004405167502 242768143829057016675085658054156069029173843566452718977789980910319968372 289318220340670045883106021427202666948428587921558828582664470923483208386 254304247593881109676724582609273741670949040469906895867342151706444640548 324707984060675446628128892371664948354047882542253609514703956739624414429 125786084546320950738753348592393927755418642173185609412108154831520915923 192033422676298173731756291271054199566981168481817292625435767748408605264 70237018464728620254434305961956673950089621204502627373468857093940647376 75218391584551901010047495874303520775865073092730040058902770251005073864 13453
|
||||
|
||||
${sleep}
|
||||
starkli call "${wormhole_address}" parse_and_verify_vm \
|
||||
|
|
|
@ -73,7 +73,7 @@ pub impl ByteArrayImpl of ByteArrayTrait {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{ByteArray, ByteArrayImpl};
|
||||
use pyth::util::array_felt252_to_bytes31;
|
||||
use pyth::util::array_try_into;
|
||||
|
||||
#[test]
|
||||
fn empty_byte_array() {
|
||||
|
@ -84,7 +84,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn byte_array_3_zeros() {
|
||||
let mut array = ByteArrayImpl::new(array_felt252_to_bytes31(array![0]), 3);
|
||||
let mut array = ByteArrayImpl::new(array_try_into(array![0]), 3);
|
||||
assert!(array.len() == 3);
|
||||
assert!(array.pop_front() == Option::Some((0.try_into().unwrap(), 3)));
|
||||
assert!(array.len() == 0);
|
||||
|
@ -93,7 +93,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn byte_array_3_bytes() {
|
||||
let mut array = ByteArrayImpl::new(array_felt252_to_bytes31(array![0x010203]), 3);
|
||||
let mut array = ByteArrayImpl::new(array_try_into(array![0x010203]), 3);
|
||||
assert!(array.len() == 3);
|
||||
assert!(array.pop_front() == Option::Some((0x010203.try_into().unwrap(), 3)));
|
||||
assert!(array.len() == 0);
|
||||
|
@ -103,7 +103,7 @@ mod tests {
|
|||
#[test]
|
||||
fn byte_array_single_full() {
|
||||
let value_31_bytes = 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f;
|
||||
let mut array = ByteArrayImpl::new(array_felt252_to_bytes31(array![value_31_bytes]), 31);
|
||||
let mut array = ByteArrayImpl::new(array_try_into(array![value_31_bytes]), 31);
|
||||
assert!(array.len() == 31);
|
||||
assert!(array.pop_front() == Option::Some((value_31_bytes.try_into().unwrap(), 31)));
|
||||
assert!(array.len() == 0);
|
||||
|
@ -115,7 +115,7 @@ mod tests {
|
|||
let value_31_bytes = 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f;
|
||||
let value2_31_bytes = 0x2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f;
|
||||
let mut array = ByteArrayImpl::new(
|
||||
array_felt252_to_bytes31(array![value_31_bytes, value2_31_bytes]), 31
|
||||
array_try_into(array![value_31_bytes, value2_31_bytes]), 31
|
||||
);
|
||||
assert!(array.len() == 62);
|
||||
assert!(array.pop_front() == Option::Some((value_31_bytes.try_into().unwrap(), 31)));
|
||||
|
@ -131,7 +131,7 @@ mod tests {
|
|||
let value2_31_bytes = 0x2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f;
|
||||
let value3_5_bytes = 0x4142434445;
|
||||
let mut array = ByteArrayImpl::new(
|
||||
array_felt252_to_bytes31(array![value_31_bytes, value2_31_bytes, value3_5_bytes]), 5
|
||||
array_try_into(array![value_31_bytes, value2_31_bytes, value3_5_bytes]), 5
|
||||
);
|
||||
assert!(array.len() == 67);
|
||||
assert!(array.pop_front() == Option::Some((value_31_bytes.try_into().unwrap(), 31)));
|
||||
|
@ -151,18 +151,18 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn byte_array_last_too_large() {
|
||||
ByteArrayImpl::new(array_felt252_to_bytes31(array![1, 2, 3]), 35);
|
||||
ByteArrayImpl::new(array_try_into(array![1, 2, 3]), 35);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn byte_array_last_zero_invalid() {
|
||||
ByteArrayImpl::new(array_felt252_to_bytes31(array![1, 2, 0]), 0);
|
||||
ByteArrayImpl::new(array_try_into(array![1, 2, 0]), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn byte_array_last_too_many_bytes() {
|
||||
ByteArrayImpl::new(array_felt252_to_bytes31(array![1, 2, 0x010203]), 2);
|
||||
ByteArrayImpl::new(array_try_into(array![1, 2, 0x010203]), 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,8 +55,7 @@ pub impl HasherImpl of HasherTrait {
|
|||
|
||||
/// Reads all remaining data from the reader and pushes it to
|
||||
/// the hashing buffer.
|
||||
fn push_reader(ref self: Hasher, ref reader: Reader) -> Result<(), pyth::reader::Error> {
|
||||
let mut result = Result::Ok(());
|
||||
fn push_reader(ref self: Hasher, ref reader: Reader) {
|
||||
while reader.len() > 0 {
|
||||
let mut chunk_len = 8 - self.num_last_bytes;
|
||||
if reader.len() < chunk_len.into() {
|
||||
|
@ -66,8 +65,7 @@ pub impl HasherImpl of HasherTrait {
|
|||
let value = reader.read_num_bytes(chunk_len);
|
||||
// chunk_len <= 8 so value must fit in u64.
|
||||
self.push_to_last(value.try_into().expect(UNEXPECTED_OVERFLOW), chunk_len);
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the keccak256 hash of the buffer. The output hash is interpreted
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::reader::{Reader, ReaderImpl};
|
|||
use super::byte_array::ByteArray;
|
||||
use super::util::ONE_SHIFT_96;
|
||||
use core::cmp::{min, max};
|
||||
use core::panic_with_felt252;
|
||||
|
||||
const MERKLE_LEAF_PREFIX: u8 = 0;
|
||||
const MERKLE_NODE_PREFIX: u8 = 1;
|
||||
|
@ -14,6 +15,15 @@ pub enum MerkleVerificationError {
|
|||
DigestMismatch,
|
||||
}
|
||||
|
||||
impl MerkleVerificationErrorIntoFelt252 of Into<MerkleVerificationError, felt252> {
|
||||
fn into(self: MerkleVerificationError) -> felt252 {
|
||||
match self {
|
||||
MerkleVerificationError::Reader(err) => err.into(),
|
||||
MerkleVerificationError::DigestMismatch => 'digest mismatch',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[generate_trait]
|
||||
impl ResultReaderToMerkleVerification<T> of ResultReaderToMerkleVerificationTrait<T> {
|
||||
fn map_err(self: Result<T, pyth::reader::Error>) -> Result<T, MerkleVerificationError> {
|
||||
|
@ -24,12 +34,11 @@ impl ResultReaderToMerkleVerification<T> of ResultReaderToMerkleVerificationTrai
|
|||
}
|
||||
}
|
||||
|
||||
fn leaf_hash(mut reader: Reader) -> Result<u256, super::reader::Error> {
|
||||
fn leaf_hash(mut reader: Reader) -> u256 {
|
||||
let mut hasher = HasherImpl::new();
|
||||
hasher.push_u8(MERKLE_LEAF_PREFIX);
|
||||
hasher.push_reader(ref reader)?;
|
||||
let hash = hasher.finalize() / ONE_SHIFT_96;
|
||||
Result::Ok(hash)
|
||||
hasher.push_reader(ref reader);
|
||||
hasher.finalize() / ONE_SHIFT_96
|
||||
}
|
||||
|
||||
fn node_hash(a: u256, b: u256) -> u256 {
|
||||
|
@ -40,25 +49,20 @@ fn node_hash(a: u256, b: u256) -> u256 {
|
|||
hasher.finalize() / ONE_SHIFT_96
|
||||
}
|
||||
|
||||
pub fn read_and_verify_proof(
|
||||
root_digest: u256, message: @ByteArray, ref reader: Reader
|
||||
) -> Result<(), MerkleVerificationError> {
|
||||
pub fn read_and_verify_proof(root_digest: u256, message: @ByteArray, ref reader: Reader) {
|
||||
let mut message_reader = ReaderImpl::new(message.clone());
|
||||
let mut current_hash = leaf_hash(message_reader.clone()).map_err()?;
|
||||
let mut current_hash = leaf_hash(message_reader.clone());
|
||||
|
||||
let proof_size = reader.read_u8();
|
||||
let mut i = 0;
|
||||
|
||||
let mut result = Result::Ok(());
|
||||
while i < proof_size {
|
||||
let sibling_digest = reader.read_u160();
|
||||
current_hash = node_hash(current_hash, sibling_digest);
|
||||
i += 1;
|
||||
};
|
||||
result?;
|
||||
|
||||
if root_digest != current_hash {
|
||||
return Result::Err(MerkleVerificationError::DigestMismatch);
|
||||
panic_with_felt252(MerkleVerificationError::DigestMismatch.into());
|
||||
}
|
||||
Result::Ok(())
|
||||
}
|
||||
|
|
|
@ -1,144 +1,27 @@
|
|||
use core::array::ArrayTrait;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use super::byte_array::ByteArray;
|
||||
use super::util::UnwrapWithFelt252;
|
||||
mod errors;
|
||||
mod interface;
|
||||
mod price_update;
|
||||
|
||||
pub use pyth::{Event, PriceFeedUpdateEvent};
|
||||
|
||||
#[starknet::interface]
|
||||
pub trait IPyth<T> {
|
||||
fn get_price_unsafe(self: @T, price_id: u256) -> Result<Price, GetPriceUnsafeError>;
|
||||
fn get_ema_price_unsafe(self: @T, price_id: u256) -> Result<Price, GetPriceUnsafeError>;
|
||||
fn set_data_sources(
|
||||
ref self: T, sources: Array<DataSource>
|
||||
) -> Result<(), GovernanceActionError>;
|
||||
fn set_fee(ref self: T, single_update_fee: u256) -> Result<(), GovernanceActionError>;
|
||||
fn update_price_feeds(ref self: T, data: ByteArray) -> Result<(), UpdatePriceFeedsError>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum GetPriceUnsafeError {
|
||||
PriceFeedNotFound,
|
||||
}
|
||||
|
||||
pub impl GetPriceUnsafeErrorUnwrapWithFelt252<T> of UnwrapWithFelt252<T, GetPriceUnsafeError> {
|
||||
fn unwrap_with_felt252(self: Result<T, GetPriceUnsafeError>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPriceUnsafeErrorIntoFelt252 of Into<GetPriceUnsafeError, felt252> {
|
||||
fn into(self: GetPriceUnsafeError) -> felt252 {
|
||||
match self {
|
||||
GetPriceUnsafeError::PriceFeedNotFound => 'price feed not found',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum GovernanceActionError {
|
||||
AccessDenied,
|
||||
}
|
||||
|
||||
pub impl GovernanceActionErrorUnwrapWithFelt252<T> of UnwrapWithFelt252<T, GovernanceActionError> {
|
||||
fn unwrap_with_felt252(self: Result<T, GovernanceActionError>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GovernanceActionErrorIntoFelt252 of Into<GovernanceActionError, felt252> {
|
||||
fn into(self: GovernanceActionError) -> felt252 {
|
||||
match self {
|
||||
GovernanceActionError::AccessDenied => 'access denied',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum UpdatePriceFeedsError {
|
||||
Reader: super::reader::Error,
|
||||
Wormhole: super::wormhole::ParseAndVerifyVmError,
|
||||
InvalidUpdateData,
|
||||
InvalidUpdateDataSource,
|
||||
InsufficientFeeAllowance,
|
||||
}
|
||||
|
||||
pub impl UpdatePriceFeedsErrorUnwrapWithFelt252<T> of UnwrapWithFelt252<T, UpdatePriceFeedsError> {
|
||||
fn unwrap_with_felt252(self: Result<T, UpdatePriceFeedsError>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdatePriceFeedsErrorIntoFelt252 of Into<UpdatePriceFeedsError, felt252> {
|
||||
fn into(self: UpdatePriceFeedsError) -> felt252 {
|
||||
match self {
|
||||
UpdatePriceFeedsError::Reader(err) => err.into(),
|
||||
UpdatePriceFeedsError::Wormhole(err) => err.into(),
|
||||
UpdatePriceFeedsError::InvalidUpdateData => 'invalid update data',
|
||||
UpdatePriceFeedsError::InvalidUpdateDataSource => 'invalid update data source',
|
||||
UpdatePriceFeedsError::InsufficientFeeAllowance => 'insufficient fee allowance',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone, Copy, Hash, Default, Serde, starknet::Store)]
|
||||
pub struct DataSource {
|
||||
pub emitter_chain_id: u16,
|
||||
pub emitter_address: u256,
|
||||
}
|
||||
|
||||
#[derive(Drop, Clone, Serde, starknet::Store)]
|
||||
struct PriceInfo {
|
||||
pub price: i64,
|
||||
pub conf: u64,
|
||||
pub expo: i32,
|
||||
pub publish_time: u64,
|
||||
pub ema_price: i64,
|
||||
pub ema_conf: u64,
|
||||
}
|
||||
|
||||
#[derive(Drop, Clone, Serde)]
|
||||
struct Price {
|
||||
pub price: i64,
|
||||
pub conf: u64,
|
||||
pub expo: i32,
|
||||
pub publish_time: u64,
|
||||
}
|
||||
pub use errors::{GetPriceUnsafeError, GovernanceActionError, UpdatePriceFeedsError};
|
||||
pub use interface::{IPyth, IPythDispatcher, IPythDispatcherTrait, DataSource, Price};
|
||||
|
||||
#[starknet::contract]
|
||||
mod pyth {
|
||||
use pyth::reader::ReaderTrait;
|
||||
use super::price_update::{
|
||||
PriceInfo, PriceFeedMessage, read_and_verify_message, read_header_and_wormhole_proof,
|
||||
parse_wormhole_proof
|
||||
};
|
||||
use pyth::reader::{Reader, ReaderImpl};
|
||||
use pyth::byte_array::{ByteArray, ByteArrayImpl};
|
||||
use core::panic_with_felt252;
|
||||
use core::starknet::{ContractAddress, get_caller_address, get_execution_info};
|
||||
use pyth::wormhole::{IWormholeDispatcher, IWormholeDispatcherTrait};
|
||||
use super::{
|
||||
DataSource, UpdatePriceFeedsError, PriceInfo, GovernanceActionError, Price,
|
||||
GetPriceUnsafeError
|
||||
DataSource, UpdatePriceFeedsError, GovernanceActionError, Price, GetPriceUnsafeError
|
||||
};
|
||||
use pyth::merkle_tree::{read_and_verify_proof, MerkleVerificationError};
|
||||
use pyth::hash::{Hasher, HasherImpl};
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use pyth::util::{u64_as_i64, u32_as_i32};
|
||||
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcherTrait, IERC20CamelDispatcher};
|
||||
|
||||
// Stands for PNAU (Pyth Network Accumulator Update)
|
||||
const ACCUMULATOR_MAGIC: u32 = 0x504e4155;
|
||||
// Stands for AUWV (Accumulator Update Wormhole Verficiation)
|
||||
const ACCUMULATOR_WORMHOLE_MAGIC: u32 = 0x41555756;
|
||||
const MAJOR_VERSION: u8 = 1;
|
||||
const MINIMUM_ALLOWED_MINOR_VERSION: u8 = 0;
|
||||
|
||||
#[event]
|
||||
#[derive(Drop, PartialEq, starknet::Event)]
|
||||
pub enum Event {
|
||||
|
@ -154,74 +37,6 @@ mod pyth {
|
|||
pub conf: u64,
|
||||
}
|
||||
|
||||
#[generate_trait]
|
||||
impl ResultReaderToUpdatePriceFeeds<T> of ResultReaderToUpdatePriceFeedsTrait<T> {
|
||||
fn map_err(self: Result<T, pyth::reader::Error>) -> Result<T, UpdatePriceFeedsError> {
|
||||
match self {
|
||||
Result::Ok(v) => Result::Ok(v),
|
||||
Result::Err(err) => Result::Err(UpdatePriceFeedsError::Reader(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[generate_trait]
|
||||
impl ResultWormholeToUpdatePriceFeeds<T> of ResultWormholeToUpdatePriceFeedsTrait<T> {
|
||||
fn map_err(
|
||||
self: Result<T, pyth::wormhole::ParseAndVerifyVmError>
|
||||
) -> Result<T, UpdatePriceFeedsError> {
|
||||
match self {
|
||||
Result::Ok(v) => Result::Ok(v),
|
||||
Result::Err(err) => Result::Err(UpdatePriceFeedsError::Wormhole(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[generate_trait]
|
||||
impl ResultMerkleToUpdatePriceFeeds<T> of ResultMerkleToUpdatePriceFeedsTrait<T> {
|
||||
fn map_err(self: Result<T, MerkleVerificationError>) -> Result<T, UpdatePriceFeedsError> {
|
||||
match self {
|
||||
Result::Ok(v) => Result::Ok(v),
|
||||
Result::Err(err) => {
|
||||
let err = match err {
|
||||
MerkleVerificationError::Reader(err) => UpdatePriceFeedsError::Reader(err),
|
||||
MerkleVerificationError::DigestMismatch => UpdatePriceFeedsError::InvalidUpdateData,
|
||||
};
|
||||
Result::Err(err)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
enum UpdateType {
|
||||
WormholeMerkle
|
||||
}
|
||||
|
||||
impl U8TryIntoUpdateType of TryInto<u8, UpdateType> {
|
||||
fn try_into(self: u8) -> Option<UpdateType> {
|
||||
if self == 0 {
|
||||
Option::Some(UpdateType::WormholeMerkle)
|
||||
} else {
|
||||
Option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
enum MessageType {
|
||||
PriceFeed
|
||||
}
|
||||
|
||||
impl U8TryIntoMessageType of TryInto<u8, MessageType> {
|
||||
fn try_into(self: u8) -> Option<MessageType> {
|
||||
if self == 0 {
|
||||
Option::Some(MessageType::PriceFeed)
|
||||
} else {
|
||||
Option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[storage]
|
||||
struct Storage {
|
||||
wormhole_address: ContractAddress,
|
||||
|
@ -264,39 +79,7 @@ mod pyth {
|
|||
self.wormhole_address.write(wormhole_address);
|
||||
self.fee_contract_address.write(fee_contract_address);
|
||||
self.single_update_fee.write(single_update_fee);
|
||||
write_data_sources(ref self, data_sources);
|
||||
}
|
||||
|
||||
fn write_data_sources(ref self: ContractState, data_sources: Array<DataSource>) {
|
||||
let num_old = self.num_data_sources.read();
|
||||
let mut i = 0;
|
||||
while i < num_old {
|
||||
let old_source = self.data_sources.read(i);
|
||||
self.is_valid_data_source.write(old_source, false);
|
||||
self.data_sources.write(i, Default::default());
|
||||
i += 1;
|
||||
};
|
||||
|
||||
self.num_data_sources.write(data_sources.len());
|
||||
i = 0;
|
||||
while i < data_sources.len() {
|
||||
let source = data_sources.at(i);
|
||||
self.is_valid_data_source.write(*source, true);
|
||||
self.data_sources.write(i, *source);
|
||||
i += 1;
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
struct PriceFeedMessage {
|
||||
price_id: u256,
|
||||
price: i64,
|
||||
conf: u64,
|
||||
expo: i32,
|
||||
publish_time: u64,
|
||||
prev_publish_time: u64,
|
||||
ema_price: i64,
|
||||
ema_conf: u64,
|
||||
self.write_data_sources(data_sources);
|
||||
}
|
||||
|
||||
#[abi(embed_v0)]
|
||||
|
@ -333,85 +116,37 @@ mod pyth {
|
|||
Result::Ok(price)
|
||||
}
|
||||
|
||||
fn set_data_sources(
|
||||
ref self: ContractState, sources: Array<DataSource>
|
||||
) -> Result<(), GovernanceActionError> {
|
||||
fn set_data_sources(ref self: ContractState, sources: Array<DataSource>) {
|
||||
if self.owner.read() != get_caller_address() {
|
||||
return Result::Err(GovernanceActionError::AccessDenied);
|
||||
panic_with_felt252(GovernanceActionError::AccessDenied.into());
|
||||
}
|
||||
write_data_sources(ref self, sources);
|
||||
Result::Ok(())
|
||||
self.write_data_sources(sources);
|
||||
}
|
||||
|
||||
fn set_fee(
|
||||
ref self: ContractState, single_update_fee: u256
|
||||
) -> Result<(), GovernanceActionError> {
|
||||
fn set_fee(ref self: ContractState, single_update_fee: u256) {
|
||||
if self.owner.read() != get_caller_address() {
|
||||
return Result::Err(GovernanceActionError::AccessDenied);
|
||||
panic_with_felt252(GovernanceActionError::AccessDenied.into());
|
||||
}
|
||||
self.single_update_fee.write(single_update_fee);
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
fn update_price_feeds(
|
||||
ref self: ContractState, data: ByteArray
|
||||
) -> Result<(), UpdatePriceFeedsError> {
|
||||
fn update_price_feeds(ref self: ContractState, data: ByteArray) {
|
||||
let mut reader = ReaderImpl::new(data);
|
||||
let x = reader.read_u32();
|
||||
if x != ACCUMULATOR_MAGIC {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateData);
|
||||
}
|
||||
if reader.read_u8() != MAJOR_VERSION {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateData);
|
||||
}
|
||||
if reader.read_u8() < MINIMUM_ALLOWED_MINOR_VERSION {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateData);
|
||||
}
|
||||
|
||||
let trailing_header_size = reader.read_u8();
|
||||
reader.skip(trailing_header_size);
|
||||
|
||||
let update_type: Option<UpdateType> = reader.read_u8().try_into();
|
||||
match update_type {
|
||||
Option::Some(v) => match v {
|
||||
UpdateType::WormholeMerkle => {}
|
||||
},
|
||||
Option::None => { return Result::Err(UpdatePriceFeedsError::InvalidUpdateData); }
|
||||
};
|
||||
|
||||
let wh_proof_size = reader.read_u16();
|
||||
let wh_proof = reader.read_byte_array(wh_proof_size.into());
|
||||
let wormhole_proof = read_header_and_wormhole_proof(ref reader);
|
||||
let wormhole = IWormholeDispatcher { contract_address: self.wormhole_address.read() };
|
||||
let vm = wormhole.parse_and_verify_vm(wh_proof).map_err()?;
|
||||
let vm = wormhole.parse_and_verify_vm(wormhole_proof);
|
||||
|
||||
let source = DataSource {
|
||||
emitter_chain_id: vm.emitter_chain_id, emitter_address: vm.emitter_address
|
||||
};
|
||||
if !self.is_valid_data_source.read(source) {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateDataSource);
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateDataSource.into());
|
||||
}
|
||||
|
||||
let mut payload_reader = ReaderImpl::new(vm.payload);
|
||||
let x = payload_reader.read_u32();
|
||||
if x != ACCUMULATOR_WORMHOLE_MAGIC {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateData);
|
||||
}
|
||||
|
||||
let update_type: Option<UpdateType> = payload_reader.read_u8().try_into();
|
||||
match update_type {
|
||||
Option::Some(v) => match v {
|
||||
UpdateType::WormholeMerkle => {}
|
||||
},
|
||||
Option::None => { return Result::Err(UpdatePriceFeedsError::InvalidUpdateData); }
|
||||
};
|
||||
|
||||
let _slot = payload_reader.read_u64();
|
||||
let _ring_size = payload_reader.read_u32();
|
||||
let root_digest = payload_reader.read_u160();
|
||||
let root_digest = parse_wormhole_proof(vm.payload);
|
||||
|
||||
let num_updates = reader.read_u8();
|
||||
|
||||
let total_fee = get_total_fee(ref self, num_updates);
|
||||
let total_fee = self.get_total_fee(num_updates);
|
||||
let fee_contract = IERC20CamelDispatcher {
|
||||
contract_address: self.fee_contract_address.read()
|
||||
};
|
||||
|
@ -419,90 +154,72 @@ mod pyth {
|
|||
let caller = execution_info.caller_address;
|
||||
let contract = execution_info.contract_address;
|
||||
if fee_contract.allowance(caller, contract) < total_fee {
|
||||
return Result::Err(UpdatePriceFeedsError::InsufficientFeeAllowance);
|
||||
panic_with_felt252(UpdatePriceFeedsError::InsufficientFeeAllowance.into());
|
||||
}
|
||||
if !fee_contract.transferFrom(caller, contract, total_fee) {
|
||||
return Result::Err(UpdatePriceFeedsError::InsufficientFeeAllowance);
|
||||
panic_with_felt252(UpdatePriceFeedsError::InsufficientFeeAllowance.into());
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut result = Result::Ok(());
|
||||
while i < num_updates {
|
||||
let r = read_and_verify_message(ref reader, root_digest);
|
||||
match r {
|
||||
Result::Ok(message) => { update_latest_price_if_necessary(ref self, message); },
|
||||
Result::Err(err) => {
|
||||
result = Result::Err(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let message = read_and_verify_message(ref reader, root_digest);
|
||||
self.update_latest_price_if_necessary(message);
|
||||
i += 1;
|
||||
};
|
||||
result?;
|
||||
|
||||
if reader.len() != 0 {
|
||||
return Result::Err(UpdatePriceFeedsError::InvalidUpdateData);
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
}
|
||||
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_and_verify_message(
|
||||
ref reader: Reader, root_digest: u256
|
||||
) -> Result<PriceFeedMessage, UpdatePriceFeedsError> {
|
||||
let message_size = reader.read_u16();
|
||||
let message = reader.read_byte_array(message_size.into());
|
||||
read_and_verify_proof(root_digest, @message, ref reader).map_err()?;
|
||||
|
||||
let mut message_reader = ReaderImpl::new(message);
|
||||
let message_type: Option<MessageType> = message_reader.read_u8().try_into();
|
||||
match message_type {
|
||||
Option::Some(v) => match v {
|
||||
MessageType::PriceFeed => {}
|
||||
},
|
||||
Option::None => { return Result::Err(UpdatePriceFeedsError::InvalidUpdateData); }
|
||||
};
|
||||
|
||||
let price_id = message_reader.read_u256();
|
||||
let price = u64_as_i64(message_reader.read_u64());
|
||||
let conf = message_reader.read_u64();
|
||||
let expo = u32_as_i32(message_reader.read_u32());
|
||||
let publish_time = message_reader.read_u64();
|
||||
let prev_publish_time = message_reader.read_u64();
|
||||
let ema_price = u64_as_i64(message_reader.read_u64());
|
||||
let ema_conf = message_reader.read_u64();
|
||||
|
||||
let message = PriceFeedMessage {
|
||||
price_id, price, conf, expo, publish_time, prev_publish_time, ema_price, ema_conf,
|
||||
};
|
||||
Result::Ok(message)
|
||||
}
|
||||
|
||||
fn update_latest_price_if_necessary(ref self: ContractState, message: PriceFeedMessage) {
|
||||
let latest_publish_time = self.latest_price_info.read(message.price_id).publish_time;
|
||||
if message.publish_time > latest_publish_time {
|
||||
let info = PriceInfo {
|
||||
price: message.price,
|
||||
conf: message.conf,
|
||||
expo: message.expo,
|
||||
publish_time: message.publish_time,
|
||||
ema_price: message.ema_price,
|
||||
ema_conf: message.ema_conf,
|
||||
#[generate_trait]
|
||||
impl PrivateImpl of PrivateTrait {
|
||||
fn write_data_sources(ref self: ContractState, data_sources: Array<DataSource>) {
|
||||
let num_old = self.num_data_sources.read();
|
||||
let mut i = 0;
|
||||
while i < num_old {
|
||||
let old_source = self.data_sources.read(i);
|
||||
self.is_valid_data_source.write(old_source, false);
|
||||
self.data_sources.write(i, Default::default());
|
||||
i += 1;
|
||||
};
|
||||
self.latest_price_info.write(message.price_id, info);
|
||||
|
||||
let event = PriceFeedUpdateEvent {
|
||||
price_id: message.price_id,
|
||||
publish_time: message.publish_time,
|
||||
price: message.price,
|
||||
conf: message.conf,
|
||||
self.num_data_sources.write(data_sources.len());
|
||||
i = 0;
|
||||
while i < data_sources.len() {
|
||||
let source = data_sources.at(i);
|
||||
self.is_valid_data_source.write(*source, true);
|
||||
self.data_sources.write(i, *source);
|
||||
i += 1;
|
||||
};
|
||||
self.emit(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_fee(ref self: ContractState, num_updates: u8) -> u256 {
|
||||
self.single_update_fee.read() * num_updates.into()
|
||||
fn update_latest_price_if_necessary(ref self: ContractState, message: PriceFeedMessage) {
|
||||
let latest_publish_time = self.latest_price_info.read(message.price_id).publish_time;
|
||||
if message.publish_time > latest_publish_time {
|
||||
let info = PriceInfo {
|
||||
price: message.price,
|
||||
conf: message.conf,
|
||||
expo: message.expo,
|
||||
publish_time: message.publish_time,
|
||||
ema_price: message.ema_price,
|
||||
ema_conf: message.ema_conf,
|
||||
};
|
||||
self.latest_price_info.write(message.price_id, info);
|
||||
|
||||
let event = PriceFeedUpdateEvent {
|
||||
price_id: message.price_id,
|
||||
publish_time: message.publish_time,
|
||||
price: message.price,
|
||||
conf: message.conf,
|
||||
};
|
||||
self.emit(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_fee(ref self: ContractState, num_updates: u8) -> u256 {
|
||||
self.single_update_fee.read() * num_updates.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum GetPriceUnsafeError {
|
||||
PriceFeedNotFound,
|
||||
}
|
||||
|
||||
impl GetPriceUnsafeErrorIntoFelt252 of Into<GetPriceUnsafeError, felt252> {
|
||||
fn into(self: GetPriceUnsafeError) -> felt252 {
|
||||
match self {
|
||||
GetPriceUnsafeError::PriceFeedNotFound => 'price feed not found',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum GovernanceActionError {
|
||||
AccessDenied,
|
||||
}
|
||||
|
||||
impl GovernanceActionErrorIntoFelt252 of Into<GovernanceActionError, felt252> {
|
||||
fn into(self: GovernanceActionError) -> felt252 {
|
||||
match self {
|
||||
GovernanceActionError::AccessDenied => 'access denied',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum UpdatePriceFeedsError {
|
||||
Reader: pyth::reader::Error,
|
||||
Wormhole: pyth::wormhole::ParseAndVerifyVmError,
|
||||
InvalidUpdateData,
|
||||
InvalidUpdateDataSource,
|
||||
InsufficientFeeAllowance,
|
||||
}
|
||||
|
||||
impl UpdatePriceFeedsErrorIntoFelt252 of Into<UpdatePriceFeedsError, felt252> {
|
||||
fn into(self: UpdatePriceFeedsError) -> felt252 {
|
||||
match self {
|
||||
UpdatePriceFeedsError::Reader(err) => err.into(),
|
||||
UpdatePriceFeedsError::Wormhole(err) => err.into(),
|
||||
UpdatePriceFeedsError::InvalidUpdateData => 'invalid update data',
|
||||
UpdatePriceFeedsError::InvalidUpdateDataSource => 'invalid update data source',
|
||||
UpdatePriceFeedsError::InsufficientFeeAllowance => 'insufficient fee allowance',
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use super::GetPriceUnsafeError;
|
||||
use pyth::byte_array::ByteArray;
|
||||
|
||||
#[starknet::interface]
|
||||
pub trait IPyth<T> {
|
||||
fn get_price_unsafe(self: @T, price_id: u256) -> Result<Price, GetPriceUnsafeError>;
|
||||
fn get_ema_price_unsafe(self: @T, price_id: u256) -> Result<Price, GetPriceUnsafeError>;
|
||||
fn set_data_sources(ref self: T, sources: Array<DataSource>);
|
||||
fn set_fee(ref self: T, single_update_fee: u256);
|
||||
fn update_price_feeds(ref self: T, data: ByteArray);
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone, Copy, Hash, Default, Serde, starknet::Store)]
|
||||
pub struct DataSource {
|
||||
pub emitter_chain_id: u16,
|
||||
pub emitter_address: u256,
|
||||
}
|
||||
|
||||
#[derive(Drop, Clone, Serde)]
|
||||
pub struct Price {
|
||||
pub price: i64,
|
||||
pub conf: u64,
|
||||
pub expo: i32,
|
||||
pub publish_time: u64,
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
use pyth::reader::{Reader, ReaderImpl};
|
||||
use pyth::pyth::UpdatePriceFeedsError;
|
||||
use core::panic_with_felt252;
|
||||
use pyth::byte_array::ByteArray;
|
||||
use pyth::merkle_tree::read_and_verify_proof;
|
||||
use pyth::util::{u32_as_i32, u64_as_i64};
|
||||
|
||||
// Stands for PNAU (Pyth Network Accumulator Update)
|
||||
const ACCUMULATOR_MAGIC: u32 = 0x504e4155;
|
||||
// Stands for AUWV (Accumulator Update Wormhole Verficiation)
|
||||
const ACCUMULATOR_WORMHOLE_MAGIC: u32 = 0x41555756;
|
||||
const MAJOR_VERSION: u8 = 1;
|
||||
const MINIMUM_ALLOWED_MINOR_VERSION: u8 = 0;
|
||||
|
||||
#[derive(Drop, Clone, Serde, starknet::Store)]
|
||||
pub struct PriceInfo {
|
||||
pub price: i64,
|
||||
pub conf: u64,
|
||||
pub expo: i32,
|
||||
pub publish_time: u64,
|
||||
pub ema_price: i64,
|
||||
pub ema_conf: u64,
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
enum UpdateType {
|
||||
WormholeMerkle
|
||||
}
|
||||
|
||||
impl U8TryIntoUpdateType of TryInto<u8, UpdateType> {
|
||||
fn try_into(self: u8) -> Option<UpdateType> {
|
||||
if self == 0 {
|
||||
Option::Some(UpdateType::WormholeMerkle)
|
||||
} else {
|
||||
Option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
enum MessageType {
|
||||
PriceFeed
|
||||
}
|
||||
|
||||
impl U8TryIntoMessageType of TryInto<u8, MessageType> {
|
||||
fn try_into(self: u8) -> Option<MessageType> {
|
||||
if self == 0 {
|
||||
Option::Some(MessageType::PriceFeed)
|
||||
} else {
|
||||
Option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop)]
|
||||
pub struct PriceFeedMessage {
|
||||
pub price_id: u256,
|
||||
pub price: i64,
|
||||
pub conf: u64,
|
||||
pub expo: i32,
|
||||
pub publish_time: u64,
|
||||
pub prev_publish_time: u64,
|
||||
pub ema_price: i64,
|
||||
pub ema_conf: u64,
|
||||
}
|
||||
|
||||
pub fn read_header_and_wormhole_proof(ref reader: Reader) -> ByteArray {
|
||||
if reader.read_u32() != ACCUMULATOR_MAGIC {
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
}
|
||||
if reader.read_u8() != MAJOR_VERSION {
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
}
|
||||
if reader.read_u8() < MINIMUM_ALLOWED_MINOR_VERSION {
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
}
|
||||
|
||||
let trailing_header_size = reader.read_u8();
|
||||
reader.skip(trailing_header_size);
|
||||
|
||||
let update_type: UpdateType = reader
|
||||
.read_u8()
|
||||
.try_into()
|
||||
.expect(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
|
||||
match update_type {
|
||||
UpdateType::WormholeMerkle => {}
|
||||
}
|
||||
|
||||
let wormhole_proof_size = reader.read_u16();
|
||||
reader.read_byte_array(wormhole_proof_size.into())
|
||||
}
|
||||
|
||||
pub fn parse_wormhole_proof(payload: ByteArray) -> u256 {
|
||||
let mut reader = ReaderImpl::new(payload);
|
||||
if reader.read_u32() != ACCUMULATOR_WORMHOLE_MAGIC {
|
||||
panic_with_felt252(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
}
|
||||
|
||||
let update_type: UpdateType = reader
|
||||
.read_u8()
|
||||
.try_into()
|
||||
.expect(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
|
||||
match update_type {
|
||||
UpdateType::WormholeMerkle => {}
|
||||
}
|
||||
|
||||
let _slot = reader.read_u64();
|
||||
let _ring_size = reader.read_u32();
|
||||
reader.read_u160()
|
||||
}
|
||||
|
||||
pub fn read_and_verify_message(ref reader: Reader, root_digest: u256) -> PriceFeedMessage {
|
||||
let message_size = reader.read_u16();
|
||||
let message = reader.read_byte_array(message_size.into());
|
||||
read_and_verify_proof(root_digest, @message, ref reader);
|
||||
|
||||
let mut message_reader = ReaderImpl::new(message);
|
||||
let message_type: MessageType = message_reader
|
||||
.read_u8()
|
||||
.try_into()
|
||||
.expect(UpdatePriceFeedsError::InvalidUpdateData.into());
|
||||
|
||||
match message_type {
|
||||
MessageType::PriceFeed => {}
|
||||
}
|
||||
|
||||
let price_id = message_reader.read_u256();
|
||||
let price = u64_as_i64(message_reader.read_u64());
|
||||
let conf = message_reader.read_u64();
|
||||
let expo = u32_as_i32(message_reader.read_u32());
|
||||
let publish_time = message_reader.read_u64();
|
||||
let prev_publish_time = message_reader.read_u64();
|
||||
let ema_price = u64_as_i64(message_reader.read_u64());
|
||||
let ema_conf = message_reader.read_u64();
|
||||
|
||||
PriceFeedMessage {
|
||||
price_id, price, conf, expo, publish_time, prev_publish_time, ema_price, ema_conf,
|
||||
}
|
||||
}
|
|
@ -105,6 +105,15 @@ pub trait UnwrapWithFelt252<T, E> {
|
|||
fn unwrap_with_felt252(self: Result<T, E>) -> T;
|
||||
}
|
||||
|
||||
pub impl UnwrapWithFelt252Impl<T, E, +Into<E, felt252>> of UnwrapWithFelt252<T, E> {
|
||||
fn unwrap_with_felt252(self: Result<T, E>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reinterpret `u64` as `i64` as if it was a two's complement binary representation.
|
||||
pub fn u64_as_i64(value: u64) -> i64 {
|
||||
if value < 0x8000000000000000 {
|
||||
|
@ -125,7 +134,7 @@ pub fn u32_as_i32(value: u32) -> i32 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn array_felt252_to_bytes31(mut input: Array<felt252>) -> Array<bytes31> {
|
||||
pub fn array_try_into<T, U, +TryInto<T, U>, +Drop<T>, +Drop<U>>(mut input: Array<T>) -> Array<U> {
|
||||
let mut output = array![];
|
||||
loop {
|
||||
match input.pop_front() {
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
use super::byte_array::ByteArray;
|
||||
use core::starknet::secp256_trait::Signature;
|
||||
use core::starknet::EthAddress;
|
||||
use pyth::util::UnwrapWithFelt252;
|
||||
|
||||
mod governance;
|
||||
|
||||
#[starknet::interface]
|
||||
pub trait IWormhole<T> {
|
||||
fn submit_new_guardian_set(
|
||||
ref self: T, set_index: u32, guardians: Array<felt252>
|
||||
) -> Result<(), SubmitNewGuardianSetError>;
|
||||
fn parse_and_verify_vm(self: @T, encoded_vm: ByteArray) -> Result<VM, ParseAndVerifyVmError>;
|
||||
fn parse_and_verify_vm(self: @T, encoded_vm: ByteArray) -> VerifiedVM;
|
||||
|
||||
// We don't need to implement other governance actions for now.
|
||||
// Instead of upgrading the Wormhole contract, we can switch to another Wormhole address
|
||||
// in the Pyth contract.
|
||||
fn submit_new_guardian_set(ref self: T, encoded_vm: ByteArray);
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone, Serde)]
|
||||
|
@ -17,7 +22,7 @@ pub struct GuardianSignature {
|
|||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone, Serde)]
|
||||
pub struct VM {
|
||||
pub struct VerifiedVM {
|
||||
pub version: u8,
|
||||
pub guardian_set_index: u32,
|
||||
pub signatures: Array<GuardianSignature>,
|
||||
|
@ -28,6 +33,34 @@ pub struct VM {
|
|||
pub sequence: u64,
|
||||
pub consistency_level: u8,
|
||||
pub payload: ByteArray,
|
||||
pub hash: u256,
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
pub enum GovernanceError {
|
||||
InvalidModule,
|
||||
InvalidAction,
|
||||
InvalidChainId,
|
||||
TrailingData,
|
||||
NotCurrentGuardianSet,
|
||||
WrongChain,
|
||||
WrongContract,
|
||||
ActionAlreadyConsumed,
|
||||
}
|
||||
|
||||
impl GovernanceErrorIntoFelt252 of Into<GovernanceError, felt252> {
|
||||
fn into(self: GovernanceError) -> felt252 {
|
||||
match self {
|
||||
GovernanceError::InvalidModule => 'invalid module',
|
||||
GovernanceError::InvalidAction => 'invalid action',
|
||||
GovernanceError::InvalidChainId => 'invalid chain ID',
|
||||
GovernanceError::TrailingData => 'trailing data',
|
||||
GovernanceError::NotCurrentGuardianSet => 'not signed by current guard.set',
|
||||
GovernanceError::WrongChain => 'wrong governance chain',
|
||||
GovernanceError::WrongContract => 'wrong governance contract',
|
||||
GovernanceError::ActionAlreadyConsumed => 'gov. action already consumed',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Drop, Debug, Serde, PartialEq)]
|
||||
|
@ -40,17 +73,6 @@ pub enum SubmitNewGuardianSetError {
|
|||
AccessDenied,
|
||||
}
|
||||
|
||||
pub impl SubmitNewGuardianSetErrorUnwrapWithFelt252<
|
||||
T
|
||||
> of UnwrapWithFelt252<T, SubmitNewGuardianSetError> {
|
||||
fn unwrap_with_felt252(self: Result<T, SubmitNewGuardianSetError>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubmitNewGuardianSetErrorIntoFelt252 of Into<SubmitNewGuardianSetError, felt252> {
|
||||
fn into(self: SubmitNewGuardianSetError) -> felt252 {
|
||||
match self {
|
||||
|
@ -76,16 +98,6 @@ pub enum ParseAndVerifyVmError {
|
|||
InvalidGuardianIndex,
|
||||
}
|
||||
|
||||
pub impl ParseAndVerifyVmErrorUnwrapWithFelt252<T> of UnwrapWithFelt252<T, ParseAndVerifyVmError> {
|
||||
fn unwrap_with_felt252(self: Result<T, ParseAndVerifyVmError>) -> T {
|
||||
match self {
|
||||
Result::Ok(v) => v,
|
||||
Result::Err(err) => core::panic_with_felt252(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl ErrorIntoFelt252 of Into<ParseAndVerifyVmError, felt252> {
|
||||
fn into(self: ParseAndVerifyVmError) -> felt252 {
|
||||
match self {
|
||||
|
@ -112,31 +124,24 @@ mod wormhole {
|
|||
use core::box::BoxTrait;
|
||||
use core::array::ArrayTrait;
|
||||
use super::{
|
||||
VM, IWormhole, GuardianSignature, quorum, ParseAndVerifyVmError, SubmitNewGuardianSetError
|
||||
VerifiedVM, IWormhole, GuardianSignature, quorum, ParseAndVerifyVmError,
|
||||
SubmitNewGuardianSetError, GovernanceError
|
||||
};
|
||||
use super::governance;
|
||||
use pyth::reader::{Reader, ReaderImpl};
|
||||
use pyth::byte_array::ByteArray;
|
||||
use core::starknet::secp256_trait::{Signature, recover_public_key, Secp256PointTrait};
|
||||
use core::starknet::secp256k1::Secp256k1Point;
|
||||
use core::starknet::{
|
||||
ContractAddress, get_execution_info, get_caller_address, get_block_timestamp
|
||||
ContractAddress, get_execution_info, get_caller_address, get_block_timestamp, EthAddress,
|
||||
};
|
||||
use core::keccak::cairo_keccak;
|
||||
use core::starknet::eth_signature::is_eth_signature_valid;
|
||||
use core::integer::u128_byte_reverse;
|
||||
use core::panic_with_felt252;
|
||||
use pyth::hash::{Hasher, HasherImpl};
|
||||
use pyth::util::{ONE_SHIFT_160, UNEXPECTED_OVERFLOW};
|
||||
|
||||
#[generate_trait]
|
||||
impl ResultReaderToWormhole<T> of ResultReaderToWormholeTrait<T> {
|
||||
fn map_err(self: Result<T, pyth::reader::Error>) -> Result<T, ParseAndVerifyVmError> {
|
||||
match self {
|
||||
Result::Ok(v) => Result::Ok(v),
|
||||
Result::Err(err) => Result::Err(ParseAndVerifyVmError::Reader(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone, Serde, starknet::Store)]
|
||||
struct GuardianSet {
|
||||
num_guardians: usize,
|
||||
|
@ -146,42 +151,46 @@ mod wormhole {
|
|||
|
||||
#[storage]
|
||||
struct Storage {
|
||||
owner: ContractAddress,
|
||||
chain_id: u16,
|
||||
governance_chain_id: u16,
|
||||
governance_contract: u256,
|
||||
current_guardian_set_index: u32,
|
||||
consumed_governance_actions: LegacyMap<u256, bool>,
|
||||
guardian_sets: LegacyMap<u32, GuardianSet>,
|
||||
// (guardian_set_index, guardian_index) => guardian_address
|
||||
guardian_keys: LegacyMap<(u32, u8), u256>,
|
||||
guardian_keys: LegacyMap<(u32, u8), EthAddress>,
|
||||
}
|
||||
|
||||
#[constructor]
|
||||
fn constructor(
|
||||
ref self: ContractState, owner: ContractAddress, initial_guardians: Array<felt252>
|
||||
ref self: ContractState,
|
||||
initial_guardians: Array<EthAddress>,
|
||||
chain_id: u16,
|
||||
governance_chain_id: u16,
|
||||
governance_contract: u256,
|
||||
) {
|
||||
self.owner.write(owner);
|
||||
self.chain_id.write(chain_id);
|
||||
self.governance_chain_id.write(governance_chain_id);
|
||||
self.governance_contract.write(governance_contract);
|
||||
let set_index = 0;
|
||||
store_guardian_set(ref self, set_index, @initial_guardians).unwrap_with_felt252();
|
||||
store_guardian_set(ref self, set_index, @initial_guardians);
|
||||
}
|
||||
|
||||
fn store_guardian_set(
|
||||
ref self: ContractState, set_index: u32, guardians: @Array<felt252>
|
||||
) -> Result<(), SubmitNewGuardianSetError> {
|
||||
fn store_guardian_set(ref self: ContractState, set_index: u32, guardians: @Array<EthAddress>) {
|
||||
if guardians.len() == 0 {
|
||||
return Result::Err(SubmitNewGuardianSetError::NoGuardiansSpecified.into());
|
||||
panic_with_felt252(SubmitNewGuardianSetError::NoGuardiansSpecified.into());
|
||||
}
|
||||
if guardians.len() >= 256 {
|
||||
return Result::Err(SubmitNewGuardianSetError::TooManyGuardians.into());
|
||||
panic_with_felt252(SubmitNewGuardianSetError::TooManyGuardians.into());
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut result = Result::Ok(());
|
||||
while i < guardians.len() {
|
||||
if *guardians.at(i) == 0 {
|
||||
result = Result::Err(SubmitNewGuardianSetError::InvalidGuardianKey.into());
|
||||
break;
|
||||
if (*guardians.at(i)).into() == 0 {
|
||||
panic_with_felt252(SubmitNewGuardianSetError::InvalidGuardianKey.into());
|
||||
}
|
||||
i += 1;
|
||||
};
|
||||
result?;
|
||||
|
||||
let set = GuardianSet { num_guardians: guardians.len(), expiration_time: 0 };
|
||||
self.guardian_sets.write(set_index, set);
|
||||
|
@ -195,7 +204,6 @@ mod wormhole {
|
|||
i += 1;
|
||||
};
|
||||
self.current_guardian_set_index.write(set_index);
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
fn expire_guardian_set(ref self: ContractState, set_index: u32, now: u64) {
|
||||
|
@ -206,43 +214,22 @@ mod wormhole {
|
|||
|
||||
#[abi(embed_v0)]
|
||||
impl WormholeImpl of IWormhole<ContractState> {
|
||||
fn submit_new_guardian_set(
|
||||
ref self: ContractState, set_index: u32, guardians: Array<felt252>
|
||||
) -> Result<(), SubmitNewGuardianSetError> {
|
||||
let execution_info = get_execution_info().unbox();
|
||||
if self.owner.read() != execution_info.caller_address {
|
||||
return Result::Err(SubmitNewGuardianSetError::AccessDenied);
|
||||
}
|
||||
let current_set_index = self.current_guardian_set_index.read();
|
||||
if set_index != current_set_index + 1 {
|
||||
return Result::Err(SubmitNewGuardianSetError::InvalidGuardianSetSequence.into());
|
||||
}
|
||||
store_guardian_set(ref self, set_index, @guardians)?;
|
||||
expire_guardian_set(
|
||||
ref self, current_set_index, execution_info.block_info.unbox().block_timestamp
|
||||
);
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
fn parse_and_verify_vm(
|
||||
self: @ContractState, encoded_vm: ByteArray
|
||||
) -> Result<VM, ParseAndVerifyVmError> {
|
||||
let (vm, body_hash) = parse_vm(encoded_vm)?;
|
||||
fn parse_and_verify_vm(self: @ContractState, encoded_vm: ByteArray) -> VerifiedVM {
|
||||
let vm = parse_vm(encoded_vm);
|
||||
let guardian_set = self.guardian_sets.read(vm.guardian_set_index);
|
||||
if guardian_set.num_guardians == 0 {
|
||||
return Result::Err(ParseAndVerifyVmError::InvalidGuardianSetIndex);
|
||||
panic_with_felt252(ParseAndVerifyVmError::InvalidGuardianSetIndex.into());
|
||||
}
|
||||
if vm.guardian_set_index != self.current_guardian_set_index.read()
|
||||
&& guardian_set.expiration_time < get_block_timestamp() {
|
||||
return Result::Err(ParseAndVerifyVmError::GuardianSetExpired);
|
||||
panic_with_felt252(ParseAndVerifyVmError::GuardianSetExpired.into());
|
||||
}
|
||||
if vm.signatures.len() < quorum(guardian_set.num_guardians) {
|
||||
return Result::Err(ParseAndVerifyVmError::NoQuorum);
|
||||
panic_with_felt252(ParseAndVerifyVmError::NoQuorum.into());
|
||||
}
|
||||
let mut signatures_clone = vm.signatures.clone();
|
||||
let mut last_index = Option::None;
|
||||
|
||||
let mut result = Result::Ok(());
|
||||
loop {
|
||||
let signature = match signatures_clone.pop_front() {
|
||||
Option::Some(v) => { v },
|
||||
|
@ -252,8 +239,7 @@ mod wormhole {
|
|||
match last_index {
|
||||
Option::Some(last_index) => {
|
||||
if *(@signature).guardian_index <= last_index {
|
||||
result = Result::Err(ParseAndVerifyVmError::InvalidSignatureOrder);
|
||||
break;
|
||||
panic_with_felt252(ParseAndVerifyVmError::InvalidSignatureOrder.into());
|
||||
}
|
||||
},
|
||||
Option::None => {},
|
||||
|
@ -261,43 +247,58 @@ mod wormhole {
|
|||
last_index = Option::Some(*(@signature).guardian_index);
|
||||
|
||||
if signature.guardian_index.into() >= guardian_set.num_guardians {
|
||||
result = Result::Err(ParseAndVerifyVmError::InvalidGuardianIndex);
|
||||
break;
|
||||
panic_with_felt252(ParseAndVerifyVmError::InvalidGuardianIndex.into());
|
||||
}
|
||||
|
||||
let guardian_key = self
|
||||
.guardian_keys
|
||||
.read((vm.guardian_set_index, signature.guardian_index));
|
||||
.read((vm.guardian_set_index, signature.guardian_index))
|
||||
.try_into()
|
||||
.expect(UNEXPECTED_OVERFLOW);
|
||||
|
||||
let r = verify_signature(body_hash, signature.signature, guardian_key);
|
||||
if r.is_err() {
|
||||
result = r;
|
||||
break;
|
||||
}
|
||||
is_eth_signature_valid(vm.hash, signature.signature, guardian_key)
|
||||
.unwrap_with_felt252();
|
||||
};
|
||||
result?;
|
||||
vm
|
||||
}
|
||||
|
||||
Result::Ok(vm)
|
||||
fn submit_new_guardian_set(ref self: ContractState, encoded_vm: ByteArray) {
|
||||
let vm = self.parse_and_verify_vm(encoded_vm);
|
||||
self.verify_governance_vm(@vm);
|
||||
let mut reader = ReaderImpl::new(vm.payload);
|
||||
let header = governance::parse_header(ref reader);
|
||||
if header.action != governance::Action::GuardianSetUpgrade {
|
||||
panic_with_felt252(GovernanceError::InvalidAction.into());
|
||||
}
|
||||
if header.chain_id != 0 && header.chain_id != self.chain_id.read() {
|
||||
panic_with_felt252(GovernanceError::InvalidChainId.into());
|
||||
}
|
||||
let new_set = governance::parse_new_guardian_set(ref reader);
|
||||
let current_set_index = self.current_guardian_set_index.read();
|
||||
if new_set.set_index != current_set_index + 1 {
|
||||
panic_with_felt252(SubmitNewGuardianSetError::InvalidGuardianSetSequence.into());
|
||||
}
|
||||
store_guardian_set(ref self, new_set.set_index, @new_set.keys);
|
||||
expire_guardian_set(ref self, current_set_index, get_block_timestamp());
|
||||
|
||||
self.consumed_governance_actions.write(vm.hash, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_signature(ref reader: Reader) -> Result<GuardianSignature, ParseAndVerifyVmError> {
|
||||
fn parse_signature(ref reader: Reader) -> GuardianSignature {
|
||||
let guardian_index = reader.read_u8();
|
||||
let r = reader.read_u256();
|
||||
let s = reader.read_u256();
|
||||
let recovery_id = reader.read_u8();
|
||||
let y_parity = (recovery_id % 2) > 0;
|
||||
let signature = GuardianSignature {
|
||||
guardian_index, signature: Signature { r, s, y_parity }
|
||||
};
|
||||
Result::Ok(signature)
|
||||
GuardianSignature { guardian_index, signature: Signature { r, s, y_parity } }
|
||||
}
|
||||
|
||||
fn parse_vm(encoded_vm: ByteArray) -> Result<(VM, u256), ParseAndVerifyVmError> {
|
||||
fn parse_vm(encoded_vm: ByteArray) -> VerifiedVM {
|
||||
let mut reader = ReaderImpl::new(encoded_vm);
|
||||
let version = reader.read_u8();
|
||||
if version != 1 {
|
||||
return Result::Err(ParseAndVerifyVmError::VmVersionIncompatible);
|
||||
panic_with_felt252(ParseAndVerifyVmError::VmVersionIncompatible.into());
|
||||
}
|
||||
let guardian_set_index = reader.read_u32();
|
||||
|
||||
|
@ -305,22 +306,14 @@ mod wormhole {
|
|||
let mut i = 0;
|
||||
let mut signatures = array![];
|
||||
|
||||
let mut result = Result::Ok(());
|
||||
while i < sig_count {
|
||||
match parse_signature(ref reader) {
|
||||
Result::Ok(signature) => { signatures.append(signature); },
|
||||
Result::Err(err) => {
|
||||
result = Result::Err(err);
|
||||
break;
|
||||
},
|
||||
}
|
||||
signatures.append(parse_signature(ref reader));
|
||||
i += 1;
|
||||
};
|
||||
result?;
|
||||
|
||||
let mut reader_for_hash = reader.clone();
|
||||
let mut hasher = HasherImpl::new();
|
||||
hasher.push_reader(ref reader_for_hash).map_err()?;
|
||||
hasher.push_reader(ref reader_for_hash);
|
||||
let body_hash1 = hasher.finalize();
|
||||
let mut hasher2 = HasherImpl::new();
|
||||
hasher2.push_u256(body_hash1);
|
||||
|
@ -335,7 +328,7 @@ mod wormhole {
|
|||
let payload_len = reader.len();
|
||||
let payload = reader.read_byte_array(payload_len);
|
||||
|
||||
let vm = VM {
|
||||
VerifiedVM {
|
||||
version,
|
||||
guardian_set_index,
|
||||
signatures,
|
||||
|
@ -346,33 +339,25 @@ mod wormhole {
|
|||
sequence,
|
||||
consistency_level,
|
||||
payload,
|
||||
};
|
||||
Result::Ok((vm, body_hash2))
|
||||
}
|
||||
|
||||
fn verify_signature(
|
||||
body_hash: u256, signature: Signature, guardian_key: u256,
|
||||
) -> Result<(), ParseAndVerifyVmError> {
|
||||
let point: Secp256k1Point = recover_public_key(body_hash, signature)
|
||||
.ok_or(ParseAndVerifyVmError::InvalidSignature)?;
|
||||
let address = eth_address(point)?;
|
||||
assert(guardian_key != 0, SubmitNewGuardianSetError::InvalidGuardianKey.into());
|
||||
if address != guardian_key {
|
||||
return Result::Err(ParseAndVerifyVmError::InvalidSignature);
|
||||
hash: body_hash2,
|
||||
}
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
fn eth_address(point: Secp256k1Point) -> Result<u256, ParseAndVerifyVmError> {
|
||||
let (x, y) = match point.get_coordinates() {
|
||||
Result::Ok(v) => { v },
|
||||
Result::Err(_) => { return Result::Err(ParseAndVerifyVmError::InvalidSignature); },
|
||||
};
|
||||
|
||||
let mut hasher = HasherImpl::new();
|
||||
hasher.push_u256(x);
|
||||
hasher.push_u256(y);
|
||||
let address = hasher.finalize() % ONE_SHIFT_160;
|
||||
Result::Ok(address)
|
||||
#[generate_trait]
|
||||
impl PrivateImpl of PrivateImplTrait {
|
||||
fn verify_governance_vm(self: @ContractState, vm: @VerifiedVM) {
|
||||
if self.current_guardian_set_index.read() != *vm.guardian_set_index {
|
||||
panic_with_felt252(GovernanceError::NotCurrentGuardianSet.into());
|
||||
}
|
||||
if self.governance_chain_id.read() != *vm.emitter_chain_id {
|
||||
panic_with_felt252(GovernanceError::WrongChain.into());
|
||||
}
|
||||
if self.governance_contract.read() != *vm.emitter_address {
|
||||
panic_with_felt252(GovernanceError::WrongContract.into());
|
||||
}
|
||||
if self.consumed_governance_actions.read(*vm.hash) {
|
||||
panic_with_felt252(GovernanceError::ActionAlreadyConsumed.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
use pyth::reader::{Reader, ReaderImpl};
|
||||
use pyth::util::UNEXPECTED_OVERFLOW;
|
||||
use super::GovernanceError;
|
||||
use core::panic_with_felt252;
|
||||
use core::starknet::EthAddress;
|
||||
|
||||
// "Core" (left padded)
|
||||
const MODULE: u256 = 0x00000000000000000000000000000000000000000000000000000000436f7265;
|
||||
|
||||
#[derive(Drop, Debug, Copy, PartialEq)]
|
||||
pub enum Action {
|
||||
ContractUpgrade,
|
||||
GuardianSetUpgrade,
|
||||
SetMessageFee,
|
||||
TransferFees,
|
||||
RecoverChainId,
|
||||
}
|
||||
|
||||
impl U8TryIntoAction of TryInto<u8, Action> {
|
||||
fn try_into(self: u8) -> Option<Action> {
|
||||
let value = match self {
|
||||
0 => { return Option::None; },
|
||||
1 => Action::ContractUpgrade,
|
||||
2 => Action::GuardianSetUpgrade,
|
||||
3 => Action::SetMessageFee,
|
||||
4 => Action::TransferFees,
|
||||
5 => Action::RecoverChainId,
|
||||
_ => { return Option::None; },
|
||||
};
|
||||
Option::Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone)]
|
||||
pub struct Header {
|
||||
pub module: u256,
|
||||
pub action: Action,
|
||||
pub chain_id: u16,
|
||||
}
|
||||
|
||||
#[derive(Drop, Debug, Clone)]
|
||||
pub struct NewGuardianSet {
|
||||
pub set_index: u32,
|
||||
pub keys: Array<EthAddress>,
|
||||
}
|
||||
|
||||
pub fn parse_header(ref reader: Reader) -> Header {
|
||||
let module = reader.read_u256();
|
||||
if module != MODULE {
|
||||
panic_with_felt252(GovernanceError::InvalidModule.into());
|
||||
}
|
||||
|
||||
let action = reader.read_u8().try_into().expect(GovernanceError::InvalidAction.into());
|
||||
let chain_id = reader.read_u16();
|
||||
Header { module, action, chain_id }
|
||||
}
|
||||
|
||||
pub fn parse_new_guardian_set(ref reader: Reader) -> NewGuardianSet {
|
||||
let set_index = reader.read_u32();
|
||||
let num_guardians = reader.read_u8();
|
||||
let mut i = 0;
|
||||
let mut keys = array![];
|
||||
while i < num_guardians {
|
||||
let key = reader.read_u160();
|
||||
keys.append(key.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||
i += 1;
|
||||
};
|
||||
assert(reader.len() == 0, GovernanceError::TrailingData.into());
|
||||
NewGuardianSet { set_index, keys }
|
||||
}
|
|
@ -6,7 +6,7 @@ use pyth::pyth::{
|
|||
IPythDispatcher, IPythDispatcherTrait, DataSource, Event as PythEvent, PriceFeedUpdateEvent
|
||||
};
|
||||
use pyth::byte_array::{ByteArray, ByteArrayImpl};
|
||||
use pyth::util::{array_felt252_to_bytes31, UnwrapWithFelt252};
|
||||
use pyth::util::{array_try_into, UnwrapWithFelt252};
|
||||
use core::starknet::ContractAddress;
|
||||
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
|
||||
|
||||
|
@ -33,7 +33,7 @@ fn decode_event(event: @Event) -> PythEvent {
|
|||
fn update_price_feeds_works() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let user = 'user'.try_into().unwrap();
|
||||
let wormhole = super::wormhole::deploy_and_init(owner);
|
||||
let wormhole = super::wormhole::deploy_and_init();
|
||||
let fee_contract = deploy_fee_contract(user);
|
||||
let pyth = deploy(
|
||||
owner,
|
||||
|
@ -55,7 +55,7 @@ fn update_price_feeds_works() {
|
|||
let mut spy = spy_events(SpyOn::One(pyth.contract_address));
|
||||
|
||||
start_prank(CheatTarget::One(pyth.contract_address), user.try_into().unwrap());
|
||||
pyth.update_price_feeds(good_update1()).unwrap_with_felt252();
|
||||
pyth.update_price_feeds(good_update1());
|
||||
stop_prank(CheatTarget::One(pyth.contract_address));
|
||||
|
||||
spy.fetch_events();
|
||||
|
@ -170,5 +170,5 @@ fn good_update1() -> ByteArray {
|
|||
226866843267230707879834616967256711063296411939069440476882347301771901839,
|
||||
95752383404870925303422787,
|
||||
];
|
||||
ByteArrayImpl::new(array_felt252_to_bytes31(bytes), 11)
|
||||
ByteArrayImpl::new(array_try_into(bytes), 11)
|
||||
}
|
||||
|
|
|
@ -2,16 +2,15 @@ use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, CheatTar
|
|||
use pyth::wormhole::{IWormholeDispatcher, IWormholeDispatcherTrait, ParseAndVerifyVmError};
|
||||
use pyth::reader::ReaderImpl;
|
||||
use pyth::byte_array::{ByteArray, ByteArrayImpl};
|
||||
use pyth::util::{UnwrapWithFelt252, array_felt252_to_bytes31};
|
||||
use core::starknet::ContractAddress;
|
||||
use pyth::util::{UnwrapWithFelt252, array_try_into};
|
||||
use core::starknet::{ContractAddress, EthAddress};
|
||||
use core::panic_with_felt252;
|
||||
|
||||
#[test]
|
||||
fn test_parse_and_verify_vm_works() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let dispatcher = deploy_and_init(owner);
|
||||
let dispatcher = deploy_and_init();
|
||||
|
||||
let vm = dispatcher.parse_and_verify_vm(good_vm1()).unwrap();
|
||||
let vm = dispatcher.parse_and_verify_vm(good_vm1());
|
||||
assert!(vm.version == 1);
|
||||
assert!(vm.guardian_set_index == 3);
|
||||
assert!(vm.signatures.len() == 13);
|
||||
|
@ -36,68 +35,144 @@ fn test_parse_and_verify_vm_works() {
|
|||
|
||||
#[test]
|
||||
#[fuzzer(runs: 100, seed: 0)]
|
||||
#[should_panic(expected: ('any_expected',))]
|
||||
#[should_panic]
|
||||
fn test_parse_and_verify_vm_rejects_corrupted_vm(pos: usize, random1: usize, random2: usize) {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let dispatcher = deploy_and_init(owner);
|
||||
let dispatcher = deploy_and_init();
|
||||
|
||||
let r = dispatcher.parse_and_verify_vm(corrupted_vm(pos, random1, random2));
|
||||
match r {
|
||||
Result::Ok(v) => { println!("no error, output: {:?}", v); },
|
||||
Result::Err(err) => {
|
||||
if err == ParseAndVerifyVmError::InvalidSignature
|
||||
|| err == ParseAndVerifyVmError::InvalidGuardianIndex
|
||||
|| err == ParseAndVerifyVmError::InvalidGuardianSetIndex
|
||||
|| err == ParseAndVerifyVmError::VmVersionIncompatible
|
||||
|| err == ParseAndVerifyVmError::Reader(pyth::reader::Error::UnexpectedEndOfInput) {
|
||||
panic_with_felt252('any_expected');
|
||||
} else {
|
||||
panic_with_felt252(err.into());
|
||||
}
|
||||
},
|
||||
}
|
||||
let input = corrupted_vm(good_vm1(), pos, random1, random2);
|
||||
let vm = dispatcher.parse_and_verify_vm(input);
|
||||
println!("no error, output: {:?}", vm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('access denied',))]
|
||||
fn test_submit_guardian_set_rejects_wrong_owner() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let dispatcher = deploy(owner, guardian_set1());
|
||||
start_prank(CheatTarget::One(dispatcher.contract_address), 'baddy'.try_into().unwrap());
|
||||
dispatcher.submit_new_guardian_set(1, guardian_set1()).unwrap_with_felt252();
|
||||
#[should_panic(expected: ('wrong governance contract',))]
|
||||
fn test_submit_guardian_set_rejects_invalid_emitter() {
|
||||
let dispatcher = deploy(
|
||||
array_try_into(array![0x686b9ea8e3237110eaaba1f1b7467559a3273819]),
|
||||
CHAIN_ID,
|
||||
GOVERNANCE_CHAIN_ID,
|
||||
GOVERNANCE_CONTRACT
|
||||
);
|
||||
|
||||
dispatcher
|
||||
.submit_new_guardian_set(
|
||||
ByteArrayImpl::new(
|
||||
array_try_into(
|
||||
array![
|
||||
1766847064779993780836504669527478016540696065743262550388106844126893447,
|
||||
69151420679589009790918040295649622139220704596068812939049771907133879935,
|
||||
104495383778385781169925874245014135708035627262536525919103632893328490496,
|
||||
6044629098073145873860096,
|
||||
1131377253,
|
||||
210626190275159008588167432483938910866205453014421218013934467097,
|
||||
]
|
||||
),
|
||||
28
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('invalid guardian set index',))]
|
||||
fn test_submit_guardian_set_rejects_wrong_index_in_signer() {
|
||||
let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
|
||||
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm1());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm3());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('invalid guardian set sequence',))]
|
||||
fn test_submit_guardian_set_rejects_wrong_index() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let dispatcher = deploy(owner, guardian_set1());
|
||||
fn test_submit_guardian_set_rejects_wrong_index_in_payload() {
|
||||
let dispatcher = deploy(
|
||||
array_try_into(array![0x686b9ea8e3237110eaaba1f1b7467559a3273819]),
|
||||
CHAIN_ID,
|
||||
GOVERNANCE_CHAIN_ID,
|
||||
GOVERNANCE_CONTRACT
|
||||
);
|
||||
|
||||
start_prank(CheatTarget::One(dispatcher.contract_address), owner.try_into().unwrap());
|
||||
dispatcher.submit_new_guardian_set(1, guardian_set1()).unwrap_with_felt252();
|
||||
dispatcher.submit_new_guardian_set(3, guardian_set3()).unwrap_with_felt252();
|
||||
dispatcher
|
||||
.submit_new_guardian_set(
|
||||
ByteArrayImpl::new(
|
||||
array_try_into(
|
||||
array![
|
||||
1766847064779992086486657352557640859156186269544082638392748527776826036,
|
||||
194277059768327503957595402526511955581212349039595919400671200491321209820,
|
||||
434496814532575177274556800095069791478767471500230428914335519265903345664,
|
||||
4835703278458516699153920,
|
||||
1131377253,
|
||||
210626190275159756877005745906233031152839803751327281851396470809,
|
||||
]
|
||||
),
|
||||
28
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('no guardians specified',))]
|
||||
fn test_deploy_rejects_empty() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
deploy(owner, array![]);
|
||||
deploy(array![], CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('no guardians specified',))]
|
||||
fn test_submit_guardian_set_rejects_empty() {
|
||||
let owner = 'owner'.try_into().unwrap();
|
||||
let dispatcher = deploy(owner, guardian_set1());
|
||||
let dispatcher = deploy(
|
||||
array_try_into(array![0x686b9ea8e3237110eaaba1f1b7467559a3273819]),
|
||||
CHAIN_ID,
|
||||
GOVERNANCE_CHAIN_ID,
|
||||
GOVERNANCE_CONTRACT
|
||||
);
|
||||
|
||||
start_prank(CheatTarget::One(dispatcher.contract_address), owner.try_into().unwrap());
|
||||
dispatcher.submit_new_guardian_set(1, array![]).unwrap_with_felt252();
|
||||
dispatcher
|
||||
.submit_new_guardian_set(
|
||||
ByteArrayImpl::new(
|
||||
array_try_into(
|
||||
array![
|
||||
1766847064779991325832211120621568385196129637393266719212748612567366167,
|
||||
101913621687013458268034923649142123047718029322567283658602535951581008800,
|
||||
334673952516423004763530105323893104621683276518933872430791864882642812928,
|
||||
4835703278458516699153920,
|
||||
1131377253,
|
||||
144116287587483904,
|
||||
]
|
||||
),
|
||||
8
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn deploy(owner: ContractAddress, guardians: Array<felt252>) -> IWormholeDispatcher {
|
||||
#[test]
|
||||
#[fuzzer(runs: 100, seed: 0)]
|
||||
#[should_panic]
|
||||
fn test_submit_guardian_set_rejects_corrupted(pos: usize, random1: usize, random2: usize) {
|
||||
let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
|
||||
|
||||
let vm = corrupted_vm(governance_upgrade_vm1(), pos, random1, random2);
|
||||
dispatcher.submit_new_guardian_set(vm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected: ('wrong governance chain',))]
|
||||
fn test_submit_guardian_set_rejects_non_governance(pos: usize, random1: usize, random2: usize) {
|
||||
let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
|
||||
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm1());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm2());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm3());
|
||||
|
||||
dispatcher.submit_new_guardian_set(good_vm1());
|
||||
}
|
||||
|
||||
fn deploy(
|
||||
guardians: Array<EthAddress>,
|
||||
chain_id: u16,
|
||||
governance_chain_id: u16,
|
||||
governance_contract: u256,
|
||||
) -> IWormholeDispatcher {
|
||||
let mut args = array![];
|
||||
(owner, guardians).serialize(ref args);
|
||||
(guardians, chain_id, governance_chain_id, governance_contract).serialize(ref args);
|
||||
let contract = declare("wormhole");
|
||||
let contract_address = match contract.deploy(@args) {
|
||||
Result::Ok(v) => { v },
|
||||
|
@ -109,22 +184,20 @@ fn deploy(owner: ContractAddress, guardians: Array<felt252>) -> IWormholeDispatc
|
|||
IWormholeDispatcher { contract_address }
|
||||
}
|
||||
|
||||
pub fn deploy_and_init(owner: ContractAddress) -> IWormholeDispatcher {
|
||||
let dispatcher = deploy(owner, guardian_set1());
|
||||
pub fn deploy_and_init() -> IWormholeDispatcher {
|
||||
let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
|
||||
|
||||
start_prank(CheatTarget::One(dispatcher.contract_address), owner.try_into().unwrap());
|
||||
dispatcher.submit_new_guardian_set(1, guardian_set1()).unwrap_with_felt252();
|
||||
dispatcher.submit_new_guardian_set(2, guardian_set2()).unwrap_with_felt252();
|
||||
dispatcher.submit_new_guardian_set(3, guardian_set3()).unwrap_with_felt252();
|
||||
stop_prank(CheatTarget::One(dispatcher.contract_address));
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm1());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm2());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm3());
|
||||
dispatcher.submit_new_guardian_set(governance_upgrade_vm4());
|
||||
|
||||
dispatcher
|
||||
}
|
||||
|
||||
fn corrupted_vm(pos: usize, random1: usize, random2: usize) -> ByteArray {
|
||||
fn corrupted_vm(mut real_data: ByteArray, pos: usize, random1: usize, random2: usize) -> ByteArray {
|
||||
let mut new_data = array![];
|
||||
|
||||
let mut real_data = good_vm1();
|
||||
// Make sure we select a position not on the last item because
|
||||
// we didn't implement corrupting an incomplete bytes31.
|
||||
let pos = pos % (real_data.len() - 31);
|
||||
|
@ -183,76 +256,8 @@ fn corrupted_byte(value: u8, random: usize) -> u8 {
|
|||
(v % 256).try_into().unwrap()
|
||||
}
|
||||
|
||||
// Below are actual guardian keys from
|
||||
// https://github.com/wormhole-foundation/wormhole-networks/tree/master/mainnetv2/guardianset
|
||||
fn guardian_set1() -> Array<felt252> {
|
||||
array![
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB,
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343,
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
|
||||
0xeB5F7389Fa26941519f0863349C223b73a6DDEE7,
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95,
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB,
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
|
||||
]
|
||||
}
|
||||
fn guardian_set2() -> Array<felt252> {
|
||||
array![
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB,
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343,
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
|
||||
0x66B9590e1c41e0B226937bf9217D1d67Fd4E91F5,
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95,
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB,
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
|
||||
]
|
||||
}
|
||||
fn guardian_set3() -> Array<felt252> {
|
||||
array![
|
||||
0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
|
||||
0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
|
||||
0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
|
||||
0x107A0086b32d7A0977926A205131d8731D39cbEB,
|
||||
0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
|
||||
0x11b39756C042441BE6D8650b69b54EbE715E2343,
|
||||
0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
|
||||
0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20,
|
||||
0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
|
||||
0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
|
||||
0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
|
||||
0xf93124b7c738843CBB89E864c862c38cddCccF95,
|
||||
0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
|
||||
0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
|
||||
0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
|
||||
0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
|
||||
0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
|
||||
0x5E1487F35515d02A92753504a8D75471b9f49EdB,
|
||||
0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
|
||||
]
|
||||
fn guardian_set0() -> Array<EthAddress> {
|
||||
array_try_into(array![0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5])
|
||||
}
|
||||
|
||||
// A random VAA pulled from Hermes.
|
||||
|
@ -290,5 +295,185 @@ fn good_vm1() -> ByteArray {
|
|||
52685537088250779930155363779405986390839624071318818148325576008719597568,
|
||||
14615204155786886573933667335033405822686404253588533,
|
||||
];
|
||||
ByteArrayImpl::new(array_felt252_to_bytes31(bytes), 22)
|
||||
ByteArrayImpl::new(array_try_into(bytes), 22)
|
||||
}
|
||||
|
||||
const CHAIN_ID: u16 = 1;
|
||||
const GOVERNANCE_CHAIN_ID: u16 = 1;
|
||||
const GOVERNANCE_CONTRACT: u256 = 4;
|
||||
|
||||
// Below are actual guardian set upgrade VAAS from
|
||||
// https://github.com/pyth-network/pyth-crosschain/blob/main/contract_manager/src/contracts/wormhole.ts#L32-L37
|
||||
fn governance_upgrade_vm1() -> ByteArray {
|
||||
let bytes = array![
|
||||
1766847064779994277746302277072294871108550301449637470263976489521154979,
|
||||
374953657095152923031303770743522269007103499920836805761143506434463979495,
|
||||
373725794026553362537846905304981854320892126869150736450761801254169477120,
|
||||
4835703278458516786446336,
|
||||
1131377253,
|
||||
3533694129556775410652111826415980944262631656421498398215501759245151417,
|
||||
145493015216602589471695207668173527044214450021182755196032581352392984224,
|
||||
267497573836069714380350521200881787609530659298168186016481773490244091266,
|
||||
443348533394886521835330696538264729103669807313401311199245411889706258110,
|
||||
200303433165499832354845293203843028338419687800279845786613090211434473108,
|
||||
37282816539161742972709083946551920068062204748477644719930149699874385462,
|
||||
111200938271608595261384934914291476246753101189480743698823215749338358345,
|
||||
5785682963869019134199015821749288033381872318410562688180948003975909269,
|
||||
372447340016996751453958019806457886428852701283870538393820846119845147788,
|
||||
33251468085387571623103303511315696691298281336333243761063342581452341650,
|
||||
323161992096034641767541451811925056802673576212351940217752194462561980347,
|
||||
55852237138651071644815135002358067220635692701051811455610533875912981641,
|
||||
190413173566657072516608762222993749133,
|
||||
];
|
||||
ByteArrayImpl::new(array_try_into(bytes), 16)
|
||||
}
|
||||
|
||||
fn governance_upgrade_vm2() -> ByteArray {
|
||||
let bytes = array![
|
||||
1766847065210651126944505525521222069599854288126726949998063840465138797,
|
||||
39054013088470866893599813322035661048501117089555726788687392536164861911,
|
||||
186918267413056900890218521593203545230034250983266377769400670103688217224,
|
||||
54214750922097681971590495378823998039261772575502204791108963815396679538,
|
||||
248994008232667872698758486001506749115615219491023036208140426934463230397,
|
||||
224235483823871042187452194579994340291351644933258737665365374081962645784,
|
||||
129444929990547403397151941456764812818993218972657847255833740800106200260,
|
||||
318548597134783137700627869311159664823693239605331630210202210299165477657,
|
||||
308852933010951129895011963941866000261904600807292935694851016610643657184,
|
||||
57272874228621364335170723193404742446392708606247574725663969156507973216,
|
||||
268057363923565984687253533797066429881117576606682526627284795527707196557,
|
||||
421894189151847402000239734668088381785344768284464330085711322870200424121,
|
||||
387584417395337067059819722404321580961380603778956902593594676080614899975,
|
||||
443523131755342451570503958659975367050637907361274652611595274647186073286,
|
||||
375107813087591446268414166006799680982485924290770541964399283524664437852,
|
||||
269085314426821465871247165234113878276592898426373369094610290261431112145,
|
||||
394348694527460459816454348661249546781513091938003106009521096332701847735,
|
||||
125670844183465056159554034633959680574572737212268749779705635378223489518,
|
||||
35053869475614771227400345921974210525173525784259894123687028214330135561,
|
||||
57544237843860512274491447149877290860624174166427313971286819807773907946,
|
||||
110681468147560408039747352809294082929396639199393789980441736520638055418,
|
||||
45709869872872997180086402576677640909777820941436708911954532772405320395,
|
||||
339910511168418517917975736269171135752028257685502872671902330279073260362,
|
||||
76482764517489607955778008190826845581092838692650194719207882266659669490,
|
||||
443663869577220861680293443959666949893574779475752540587040489501289361777,
|
||||
231057874919577223790659840464529054850239319545221055959374917590157019925,
|
||||
309066533217885002074480704480667619809952056265738927105682076502747220549,
|
||||
212379788814604791028007106821871908074818251907335322546331543385945316762,
|
||||
165408661499085325620077702639227003047567884011538988728381864749733773312,
|
||||
29852013947978990147012099107546124222651092940097518043136,
|
||||
5874446556610227706402640854088357165514903,
|
||||
314635470832203526600706472223155382046271943513513368538979543914002758100,
|
||||
289993023590817330918274026889451152915026890048318491140264484864242055689,
|
||||
211265316833000774821515110003986084297271807500310630074520699505436206838,
|
||||
314620948986744608212517578488307826224331071350776523303159889004405167502,
|
||||
242768143829057016675085776170635413106817756232919004913342240722183648628,
|
||||
289318220340670045883106021427202666948428587921558828582664470923483208386,
|
||||
254304247593881109676724582609273741670949040469906895867342151706444640548,
|
||||
324707984060675446628128892371664948354047882542253609514703956739624414429,
|
||||
125786084546320950738753348592393927755418642173185609412108154831520915923,
|
||||
192033422676298173731756291271054199566981168481817292625435767748408605264,
|
||||
70237018464728620254434305961956673950089621204502627373468857093940647376,
|
||||
75218391584551901010047495874303520775865073092730040058902770251005073864,
|
||||
13453,
|
||||
];
|
||||
ByteArrayImpl::new(array_try_into(bytes), 2)
|
||||
}
|
||||
|
||||
fn governance_upgrade_vm3() -> ByteArray {
|
||||
let bytes = array![
|
||||
1766847065622031860560134801367788401015571316785630090767859240961980367,
|
||||
408239335069601434456324970231880063141100099721451058487412176729277688481,
|
||||
239499689753305520381601038928513796227317320911002802551444547638809838552,
|
||||
377515301744513788082523380503265415136454305699441419871183462725292421897,
|
||||
293792427782284265052215516935690252661713253004854348809536189867737815900,
|
||||
307592266914902727916633292174670243188255704510048236277225897328900269063,
|
||||
127373290139474278928992577974696343462455769904046193125018730285162391253,
|
||||
391788800785481654990215164673817619378887263909639120513493454202816019863,
|
||||
410413307118599096084169722886408584518140871169074821252461819158667354254,
|
||||
18837648490111595970198935552266546643395427923804444528866768515056419823,
|
||||
29964034682984173558839379357821569529808274426015494950430380078317881569,
|
||||
86017868501532670528023530422115758730056738654625156800662778409971102579,
|
||||
316587967137295297243489759859408971025377360462781809717927347025414193161,
|
||||
412080542369789462767669836400697110505430973769191785499739175360336337147,
|
||||
342817079347905714229318925597762381802367663565411998187223317628701911440,
|
||||
323381353160339090772037140072061985169258958022395380273676898316834639836,
|
||||
199931590715070935127318740956564588449721873695471932311700469202637695100,
|
||||
53310522180389647586576928116330850824055549848985438538201222342553700451,
|
||||
387322343922164253479438966163491855981414317104760621828688810466847848718,
|
||||
81609701542274539489711635515209037026645626576756528749469616228397567798,
|
||||
182108205861564989333892774796475580877981373947799860454217397980367659628,
|
||||
21549663410658134468902761710868642321546772465973442277960059676129502668,
|
||||
189434039785735939400321781125039794740638779195156759980704929066694157130,
|
||||
52255833533187953003213955242027099690232530588872309460610106220279805641,
|
||||
197105018621162723372171195601447549272902142615124680111298974553437412361,
|
||||
243585516151555343004264928593678764289083751554802049062044286334698216184,
|
||||
98577806073901898829375415748245478967425496216912736575886605480181121443,
|
||||
92916551389967933235240931764170084503123511470557201449603712010638670912,
|
||||
279247190794260779926452059689914005511524938154821508635388069101252378624,
|
||||
27765181507524306000048567556593270127801507143251178553344,
|
||||
5874446556610227706402640926145951203442839,
|
||||
314635470832203526600706472223155382046271943513513368538979543914002758100,
|
||||
289993023590817330918274026889451152915026890048318491140264484864242055689,
|
||||
211265316833000774821515110003986084297271807500310630074520699505436206838,
|
||||
314620948986744608212517578488307826224331071350776523303159889004405167502,
|
||||
242768143829057016675085658054156069029173843566452718977789980910319968372,
|
||||
289318220340670045883106021427202666948428587921558828582664470923483208386,
|
||||
254304247593881109676724582609273741670949040469906895867342151706444640548,
|
||||
324707984060675446628128892371664948354047882542253609514703956739624414429,
|
||||
125786084546320950738753348592393927755418642173185609412108154831520915923,
|
||||
192033422676298173731756291271054199566981168481817292625435767748408605264,
|
||||
70237018464728620254434305961956673950089621204502627373468857093940647376,
|
||||
75218391584551901010047495874303520775865073092730040058902770251005073864,
|
||||
13453,
|
||||
];
|
||||
ByteArrayImpl::new(array_try_into(bytes), 2)
|
||||
}
|
||||
|
||||
fn governance_upgrade_vm4() -> ByteArray {
|
||||
let bytes = array![
|
||||
1766847066033426987337757245669159273063358729535478806850006662056807068,
|
||||
191023158244075433218055661747029015323596061316379687901032561397223546211,
|
||||
30156550775609732785124128084945604136341937408029517653427049258063209215,
|
||||
301841618969457377999846355946508544313297803407604349411042057045510372286,
|
||||
399879387152070823070522891203531321261797829310211644637928969034931151834,
|
||||
1184971666775858810527395126763859219514013163556756790208661779020321698,
|
||||
427827873217506136303198988655697899138087317492051993053159867826892618987,
|
||||
55439109913191967501571602277685262841453050617358377329061538069328212552,
|
||||
34944602254693785869427132065664922748183924456022812505745784482260734500,
|
||||
50091615215549712387991200985741575718080363004681463525186508796585379155,
|
||||
265247833149227842278059484961926330281584344437952973839486092319885300192,
|
||||
421631446041795295328070636491346018953171276542115189082171457479754499396,
|
||||
59057903625576869235407103565877017330396402246452653660114888284545941770,
|
||||
315797852826246435174946736461540321579373154656484006452063031513301027405,
|
||||
9521420622979958910372839981791309896262328383324674284772682980734269170,
|
||||
272964069264268937653695089515793248726920319914036642027008415285406913245,
|
||||
194708434228888226032102758315234166672190899487218971410889219134701358728,
|
||||
117864954129109327302856065706421701676973859697066630532570005860486924893,
|
||||
323457021720552374478769194145226061243431674370101604382965685057422991463,
|
||||
327482733702858147057975319784026874245182397914737119038454598086198587150,
|
||||
159726033816658034104416471293601013976445904149240898589368461412472508473,
|
||||
165970343982649234398221341351816767302457220504375238905210573566962780340,
|
||||
66269488760319836583658182431744051236825244016843316092957806563966254500,
|
||||
360882001282595740056823749884962228392082962172369522212117195988772429063,
|
||||
202692667772209236945884489592750537635169234501360011152939202347962132650,
|
||||
407257364829649465305126488148712878739144584682351279109461295389594525334,
|
||||
270499607712829989691415988895838806019492861138165540862008308077962735002,
|
||||
388443296961168536186587069708212659389994895697827691755155284015603161464,
|
||||
45068266527940236008536134081672474027695203549460934893262212861351952384,
|
||||
31319268777966350508118557206583844424308993254125039779840,
|
||||
5874446556610227706402640998203302487747647,
|
||||
204224545225244051821590480758420624947979343122083461045877549162059250132,
|
||||
289993023590817330918274026889451152915026890048318491140264484864242055689,
|
||||
211265316833000774821515110003986084297271807500310630074520699505436206838,
|
||||
314620948986744608212517578488307826224331071350776523303159889004405167502,
|
||||
242768143829057016675085658054156069029173843566452718977789980910319968372,
|
||||
289318220340670045883106021427202666948428587921558828582664470923483208386,
|
||||
254304247593881109676724582609273741670949040469906895867342151706444640548,
|
||||
324707984060675446628128892371664948354047882542253609514703956739624414429,
|
||||
125786084546320950738753348592393927755418642173185609412108154831520915923,
|
||||
192033422676298173731756291271054199566981168481817292625435767748408605264,
|
||||
70237018464728620254434305961956673950089621204502627373468857093940647376,
|
||||
75218391584551901010047495874303520775865073092730040058902770251005073864,
|
||||
13453,
|
||||
];
|
||||
ByteArrayImpl::new(array_try_into(bytes), 2)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue