sdk: add underlying sdk for wormhole programs
Change-Id: I858f3e43e6458af51131de9165a63078e4bb024c
This commit is contained in:
parent
97566d878a
commit
ee0fea0436
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"core",
|
"core",
|
||||||
|
"sdk"
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
[package]
|
||||||
|
name = "wormhole-sdk"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Helper methods will target the Wormhole mainnet contract addresses.
|
||||||
|
mainnet = []
|
||||||
|
|
||||||
|
# Helper methosd will target the Wormhole devnet contract addresses.
|
||||||
|
devnet = []
|
||||||
|
|
||||||
|
# Enable Optional dependencies that are only required when targetting Terra.
|
||||||
|
terra = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cosmwasm-storage",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"wormhole-bridge-terra",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Enable Optional dependencies that are only required when targetting Solana.
|
||||||
|
solana = [
|
||||||
|
"solana-program",
|
||||||
|
"wormhole-bridge-solana",
|
||||||
|
]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
lto = "thin"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
borsh = { version="0.8.1" }
|
||||||
|
nom = { version="7", default-features=false, features=["alloc"] }
|
||||||
|
primitive-types = { version = "0.9.0", default-features = false }
|
||||||
|
wormhole-core = { path="../core", version="0.1.0" }
|
||||||
|
|
||||||
|
# Solana Specific
|
||||||
|
solana-program = { version="1.7.0", optional=true }
|
||||||
|
|
||||||
|
# Terra Specific
|
||||||
|
cosmwasm-std = { version = "0.16.0", optional=true }
|
||||||
|
cosmwasm-storage = { version = "0.16.0", optional=true }
|
||||||
|
schemars = { version = "0.8.1", optional=true }
|
||||||
|
serde = { version = "1.0.103", default-features = false, features = ["derive"], optional=true }
|
||||||
|
|
||||||
|
[dependencies.wormhole-bridge-solana]
|
||||||
|
path = "../../../solana/bridge/program"
|
||||||
|
version = "0.1.0"
|
||||||
|
optional = true
|
||||||
|
features = [ "no-entrypoint" ]
|
||||||
|
|
||||||
|
[dependencies.wormhole-bridge-terra]
|
||||||
|
path = "../../../terra/contracts/wormhole"
|
||||||
|
version = "0.1.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
byteorder = "*"
|
||||||
|
hex = "*"
|
|
@ -0,0 +1,7 @@
|
||||||
|
[build]
|
||||||
|
rustflags = [
|
||||||
|
"-Cpasses=sancov-module",
|
||||||
|
"-Cllvm-args=-sanitizer-coverage-level=3",
|
||||||
|
"-Cllvm-args=-sanitizer-coverage-inline-8bit-counters",
|
||||||
|
"-Zsanitizer=address",
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
name = "wormhole-sdk-fuzz"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libfuzzer-sys = "0.4"
|
||||||
|
|
||||||
|
[dependencies.wormhole-sdk]
|
||||||
|
path = ".."
|
||||||
|
features = ["solana", "vaa"]
|
||||||
|
|
||||||
|
# Create isolated workspace.
|
||||||
|
[workspace]
|
||||||
|
members = ["."]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "vaa"
|
||||||
|
path = "fuzzers/vaa.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "governance"
|
||||||
|
path = "fuzzers/governance.rs"
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use wormhole_sdk::VAA;
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
VAA::from_bytes(data);
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use wormhole_sdk::vaa::VAA;
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
VAA::from_bytes(data);
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
//! Exposes an API implementation depending on which feature flags have been toggled for the
|
||||||
|
//! library. Check submodules for chain runtime specific documentation.
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(feature = "solana")]
|
||||||
|
pub mod solana;
|
||||||
|
#[cfg(feature = "solana")]
|
||||||
|
pub use solana::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(feature = "terra")]
|
||||||
|
pub mod terra;
|
||||||
|
#[cfg(feature = "terra")]
|
||||||
|
pub use terra::*;
|
|
@ -0,0 +1,134 @@
|
||||||
|
use borsh::BorshDeserialize;
|
||||||
|
use solana_program::pubkey::Pubkey;
|
||||||
|
use solana_program::account_info::AccountInfo;
|
||||||
|
use solana_program::entrypoint::ProgramResult;
|
||||||
|
use solana_program::program::invoke_signed;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
// Export Bridge API
|
||||||
|
pub use bridge::BridgeConfig;
|
||||||
|
pub use bridge::BridgeData;
|
||||||
|
pub use bridge::MessageData;
|
||||||
|
pub use bridge::PostVAAData;
|
||||||
|
pub use bridge::PostedVAAData;
|
||||||
|
pub use bridge::VerifySignaturesData;
|
||||||
|
pub use bridge::instructions;
|
||||||
|
pub use bridge::solitaire as bridge_entrypoint;
|
||||||
|
pub use bridge::types::ConsistencyLevel;
|
||||||
|
|
||||||
|
use wormhole_core::WormholeError;
|
||||||
|
use wormhole_core::VAA;
|
||||||
|
|
||||||
|
/// Export Core Mainnet Contract Address
|
||||||
|
#[cfg(feature = "mainnet")]
|
||||||
|
pub fn id() -> Pubkey {
|
||||||
|
Pubkey::from_str("worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Export Core Devnet Contract Address
|
||||||
|
#[cfg(feature = "testnet")]
|
||||||
|
pub fn id() -> Pubkey {
|
||||||
|
Pubkey::from_str("3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Export Local Tilt Devnet Contract Address
|
||||||
|
#[cfg(feature = "devnet")]
|
||||||
|
pub fn id() -> Pubkey {
|
||||||
|
Pubkey::from_str("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the Wormhole configuration account address.
|
||||||
|
pub fn config(id: &Pubkey) -> Pubkey {
|
||||||
|
let (config, _) = Pubkey::find_program_address(&[b"Bridge"], &id);
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the Wormhole fee account address, users of the bridge must pay this address before
|
||||||
|
/// submitting messages to the bridge.
|
||||||
|
pub fn fee_collector(id: &Pubkey) -> Pubkey {
|
||||||
|
let (fee_collector, _) = Pubkey::find_program_address(&[b"fee_collector"], &id);
|
||||||
|
fee_collector
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the sequence address for an emitter, which is incremented after each message post.
|
||||||
|
pub fn sequence(id: &Pubkey, emitter: &Pubkey) -> Pubkey {
|
||||||
|
let (sequence, _) = Pubkey::find_program_address(&[b"Sequence", &emitter.to_bytes()], &id);
|
||||||
|
sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the emitter address for a Solana contract, the emitter on Solana must be a signer, this
|
||||||
|
/// function helps generate a PDA and bump seed so users can emit using a PDA as the emitter.
|
||||||
|
pub fn emitter(id: &Pubkey) -> (Pubkey, Vec<&[u8]>, u8) {
|
||||||
|
let seeds = &["emitter".as_bytes()];
|
||||||
|
let (emitter, bump) = Pubkey::find_program_address(seeds, id);
|
||||||
|
(emitter, seeds.to_vec(), bump)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize helper the BridgeConfig from a Wormhole config account.
|
||||||
|
pub fn read_config(config: &AccountInfo) -> Result<BridgeConfig, WormholeError> {
|
||||||
|
let bridge_data = BridgeData::try_from_slice(&config.data.borrow())
|
||||||
|
.map_err(|_| WormholeError::DeserializeFailed)?;
|
||||||
|
Ok(bridge_data.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize helper for parsing from Borsh encoded VAA's from Solana accounts.
|
||||||
|
pub fn read_vaa(vaa: &AccountInfo) -> Result<PostedVAAData, WormholeError> {
|
||||||
|
Ok(PostedVAAData::try_from_slice(&vaa.data.borrow())
|
||||||
|
.map_err(|_| WormholeError::DeserializeFailed)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This helper method wraps the steps required to invoke Wormhole, it takes care of fee payment,
|
||||||
|
/// emitter derivation, and function invocation. This will be the right thing to use if you need to
|
||||||
|
/// simply emit a message in the most straight forward way possible.
|
||||||
|
pub fn post_message(
|
||||||
|
program_id: Pubkey,
|
||||||
|
payer: Pubkey,
|
||||||
|
message: Pubkey,
|
||||||
|
payload: impl AsRef<[u8]>,
|
||||||
|
consistency: ConsistencyLevel,
|
||||||
|
seeds: Option<&[&[u8]]>,
|
||||||
|
accounts: &[AccountInfo],
|
||||||
|
nonce: u32,
|
||||||
|
) -> ProgramResult {
|
||||||
|
// Derive any necessary Pubkeys, derivation makes sure that we match the accounts the are being
|
||||||
|
// provided by the user as well.
|
||||||
|
let id = id();
|
||||||
|
let fee_collector = fee_collector(&id);
|
||||||
|
let (emitter, mut emitter_seeds, bump) = emitter(&program_id);
|
||||||
|
let bump = &[bump];
|
||||||
|
emitter_seeds.push(bump);
|
||||||
|
|
||||||
|
// Filter for the Config AccountInfo so we can access its data.
|
||||||
|
let config = config(&id);
|
||||||
|
let config = accounts.iter().find(|item| *item.key == config).unwrap();
|
||||||
|
let config = read_config(config).unwrap();
|
||||||
|
|
||||||
|
// Pay Fee to the Wormhole
|
||||||
|
invoke_signed(
|
||||||
|
&solana_program::system_instruction::transfer(
|
||||||
|
&payer,
|
||||||
|
&fee_collector,
|
||||||
|
config.fee
|
||||||
|
),
|
||||||
|
accounts,
|
||||||
|
&[],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Invoke the Wormhole post_message endpoint to create an on-chain message.
|
||||||
|
invoke_signed(
|
||||||
|
&instructions::post_message(
|
||||||
|
id,
|
||||||
|
payer,
|
||||||
|
emitter,
|
||||||
|
message,
|
||||||
|
nonce,
|
||||||
|
payload.as_ref().to_vec(),
|
||||||
|
consistency,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
accounts,
|
||||||
|
&[&emitter_seeds, seeds.unwrap_or(&[])],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
use cosmwasm_std::{
|
||||||
|
to_binary,
|
||||||
|
Addr,
|
||||||
|
Binary,
|
||||||
|
CosmosMsg,
|
||||||
|
DepsMut,
|
||||||
|
Env,
|
||||||
|
QueryRequest,
|
||||||
|
StdResult,
|
||||||
|
WasmMsg,
|
||||||
|
WasmQuery,
|
||||||
|
};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use bridge::msg::{
|
||||||
|
ExecuteMsg,
|
||||||
|
QueryMsg,
|
||||||
|
};
|
||||||
|
use bridge::state::ParsedVAA;
|
||||||
|
|
||||||
|
/// Export Core Mainnet Contract Address
|
||||||
|
#[cfg(feature = "mainnet")]
|
||||||
|
pub fn id() -> Addr {
|
||||||
|
Addr::unchecked("terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Export Core Devnet Contract Address
|
||||||
|
#[cfg(feature = "devnet")]
|
||||||
|
pub fn id() -> Addr {
|
||||||
|
Addr::unchecked("terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post_message<T>(wormhole: Addr, nonce: u32, message: &T) -> StdResult<CosmosMsg>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
Ok(CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
|
contract_addr: wormhole.to_string(),
|
||||||
|
funds: vec![],
|
||||||
|
msg: to_binary(&ExecuteMsg::PostMessage {
|
||||||
|
message: to_binary(message)?,
|
||||||
|
nonce,
|
||||||
|
})?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a VAA using the Wormhole contract Query interface.
|
||||||
|
pub fn parse_vaa(
|
||||||
|
wormhole: Addr,
|
||||||
|
deps: DepsMut,
|
||||||
|
env: Env,
|
||||||
|
data: &Binary,
|
||||||
|
) -> StdResult<ParsedVAA> {
|
||||||
|
let vaa: ParsedVAA = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
|
||||||
|
contract_addr: wormhole.to_string(),
|
||||||
|
msg: to_binary(&QueryMsg::VerifyVAA {
|
||||||
|
vaa: data.clone(),
|
||||||
|
block_time: env.block.time.seconds(),
|
||||||
|
})?,
|
||||||
|
}))?;
|
||||||
|
Ok(vaa)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
//! This SDK provides API's for implementing cross-chain message passing via the Wormhole protocol.
|
||||||
|
//! This package aims to provide a consistent API regardless of the underlying runtime, but some
|
||||||
|
//! types will differ depending on which implementation is being targeted.
|
||||||
|
//!
|
||||||
|
//! Each implementation can be toggled using feature flags, which will switch out the underlying
|
||||||
|
//! depenencies to pull in the depenendices for the corresponding runtimes.
|
||||||
|
//!
|
||||||
|
//! Implementations:
|
||||||
|
//!
|
||||||
|
//! Runtime | Feature Flag | Version
|
||||||
|
//! ----------|-------------------------|----------------------------------------------------
|
||||||
|
//! Solana | --feature=solana | solana-sdk 1.7.1
|
||||||
|
//! Terra | --feature=terra | cosmos-sdk 0.16.0
|
||||||
|
//!
|
||||||
|
//! Docs specific to each blockchain's runtime can be found in submodules within the chains module
|
||||||
|
//! at the root of this package.
|
||||||
|
|
||||||
|
pub mod chains;
|
||||||
|
|
||||||
|
pub use wormhole_core::*;
|
||||||
|
pub use chains::*;
|
|
@ -28,7 +28,7 @@ pub type PostedMessage<'a, const State: AccountState> = Data<'a, PostedMessageDa
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PostedMessageData(pub MessageData);
|
pub struct PostedMessageData(pub MessageData);
|
||||||
|
|
||||||
#[derive(Default, BorshSerialize, BorshDeserialize, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, BorshSerialize, BorshDeserialize, Clone, Serialize, Deserialize)]
|
||||||
pub struct MessageData {
|
pub struct MessageData {
|
||||||
/// Header of the posted VAA
|
/// Header of the posted VAA
|
||||||
pub vaa_version: u8,
|
pub vaa_version: u8,
|
||||||
|
|
Loading…
Reference in New Issue