Compare commits
2 Commits
dc6b868268
...
0fdd3f0ecf
Author | SHA1 | Date |
---|---|---|
A5 Pickle | 0fdd3f0ecf | |
A5 Pickle | edaafbb5f5 |
|
@ -2377,7 +2377,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wormhole-cctp-solana"
|
||||
version = "0.0.1-alpha.7"
|
||||
version = "0.0.1-alpha.9"
|
||||
dependencies = [
|
||||
"anchor-lang",
|
||||
"anchor-spl",
|
||||
|
@ -2393,7 +2393,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wormhole-circle-integration-solana"
|
||||
version = "0.0.1-alpha.7"
|
||||
version = "0.0.1-alpha.9"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"anchor-lang",
|
||||
|
@ -2424,9 +2424,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wormhole-io"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4965f46f7a99debe3c2cf9337c6e3eb7068da348aecf074a3e35686937f25c65"
|
||||
checksum = "b021a14ea7bcef9517ed9f81d4466c4a663dd90e726c5724707a976fa83ad8f3"
|
||||
|
||||
[[package]]
|
||||
name = "wormhole-raw-vaas"
|
||||
|
|
|
@ -7,7 +7,7 @@ resolver = "2"
|
|||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
version = "0.0.1-alpha.7"
|
||||
version = "0.0.1-alpha.9"
|
||||
authors = ["Wormhole Contributors"]
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://wormhole.com"
|
||||
|
@ -31,7 +31,7 @@ version = "0.28.0"
|
|||
features = ["derive", "init-if-needed"]
|
||||
|
||||
[workspace.dependencies]
|
||||
wormhole-io = "0.1.1"
|
||||
wormhole-io = "0.1.3"
|
||||
anchor-spl = "0.28.0"
|
||||
solana-program = "1.16.16"
|
||||
hex = "0.4.3"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::{cctp, messages::Deposit, wormhole::core_bridge_program};
|
||||
use anchor_lang::prelude::*;
|
||||
use wormhole_io::TypePrefixedPayload;
|
||||
|
||||
/// Arguments used to burn Circle-supported tokens and publish a Wormhole Core Bridge message.
|
||||
#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct BurnAndPublishArgs {
|
||||
pub struct BurnAndPublishArgs<P: TypePrefixedPayload> {
|
||||
/// Token account where assets originated from. This pubkey is encoded in the [Deposit] message.
|
||||
/// If this will be useful to an integrator, he should encode where the assets have been burned
|
||||
/// from if it was not burned directly when calling [burn_and_publish].
|
||||
|
@ -29,7 +30,7 @@ pub struct BurnAndPublishArgs {
|
|||
|
||||
/// Arbitrary payload, which can be used to encode instructions or data for another network's
|
||||
/// smart contract.
|
||||
pub payload: Vec<u8>,
|
||||
pub payload: P,
|
||||
}
|
||||
|
||||
/// Method to publish a Wormhole Core Bridge message alongside a CCTP message that burns a
|
||||
|
@ -39,7 +40,7 @@ pub struct BurnAndPublishArgs {
|
|||
/// assets originated from. A program calling this method will not necessarily be burning assets
|
||||
/// from this token account directly. So this field is used to indicate the origin of the burned
|
||||
/// assets.
|
||||
pub fn burn_and_publish<'info>(
|
||||
pub fn burn_and_publish<'info, P>(
|
||||
cctp_ctx: CpiContext<
|
||||
'_,
|
||||
'_,
|
||||
|
@ -48,8 +49,11 @@ pub fn burn_and_publish<'info>(
|
|||
cctp::token_messenger_minter_program::cpi::DepositForBurnWithCaller<'info>,
|
||||
>,
|
||||
wormhole_ctx: CpiContext<'_, '_, '_, 'info, core_bridge_program::cpi::PostMessage<'info>>,
|
||||
args: BurnAndPublishArgs,
|
||||
) -> Result<u64> {
|
||||
args: BurnAndPublishArgs<P>,
|
||||
) -> Result<u64>
|
||||
where
|
||||
P: TypePrefixedPayload,
|
||||
{
|
||||
let BurnAndPublishArgs {
|
||||
burn_source,
|
||||
destination_caller,
|
||||
|
|
|
@ -7,7 +7,7 @@ use ruint::aliases::U256;
|
|||
use wormhole_io::{Readable, TypePrefixedPayload, Writeable};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Deposit {
|
||||
pub struct Deposit<P: TypePrefixedPayload> {
|
||||
pub token_address: [u8; 32],
|
||||
pub amount: U256,
|
||||
pub source_cctp_domain: u32,
|
||||
|
@ -16,14 +16,14 @@ pub struct Deposit {
|
|||
pub burn_source: [u8; 32],
|
||||
pub mint_recipient: [u8; 32],
|
||||
/// NOTE: This payload length is encoded as u16.
|
||||
pub payload: Vec<u8>,
|
||||
pub payload: P,
|
||||
}
|
||||
|
||||
impl TypePrefixedPayload for Deposit {
|
||||
impl<P: TypePrefixedPayload> TypePrefixedPayload for Deposit<P> {
|
||||
const TYPE: Option<u8> = Some(1);
|
||||
}
|
||||
|
||||
impl Readable for Deposit {
|
||||
impl<P: TypePrefixedPayload> Readable for Deposit<P> {
|
||||
const SIZE: Option<usize> = None;
|
||||
|
||||
fn read<R>(reader: &mut R) -> io::Result<Self>
|
||||
|
@ -40,10 +40,13 @@ impl Readable for Deposit {
|
|||
let mint_recipient = Readable::read(reader)?;
|
||||
|
||||
let payload_len = u16::read(reader).map(usize::from)?;
|
||||
let mut payload = Vec::with_capacity(payload_len);
|
||||
reader.read_to_end(&mut payload)?;
|
||||
|
||||
if payload.len() == payload_len {
|
||||
let payload = P::read_payload(reader)?;
|
||||
if payload.payload_written_size() != payload_len {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"payload length mismatch",
|
||||
));
|
||||
} else {
|
||||
Ok(Self {
|
||||
token_address,
|
||||
amount,
|
||||
|
@ -54,15 +57,13 @@ impl Readable for Deposit {
|
|||
mint_recipient,
|
||||
payload,
|
||||
})
|
||||
} else {
|
||||
Err(io::ErrorKind::InvalidData.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for Deposit {
|
||||
impl<P: TypePrefixedPayload> Writeable for Deposit<P> {
|
||||
fn written_size(&self) -> usize {
|
||||
32 + 32 + 4 + 4 + 8 + 32 + 32 + 2 + self.payload.len()
|
||||
32 + 32 + 4 + 4 + 8 + 32 + 32 + 2 + self.payload.payload_written_size()
|
||||
}
|
||||
|
||||
fn write<W>(&self, writer: &mut W) -> std::io::Result<()>
|
||||
|
@ -77,10 +78,10 @@ impl Writeable for Deposit {
|
|||
self.cctp_nonce.write(writer)?;
|
||||
self.burn_source.write(writer)?;
|
||||
self.mint_recipient.write(writer)?;
|
||||
u16::try_from(self.payload.len())
|
||||
u16::try_from(self.payload.payload_written_size())
|
||||
.map_err(|_| std::io::ErrorKind::InvalidData.into())
|
||||
.and_then(|len| len.write(writer))?;
|
||||
writer.write_all(&self.payload)?;
|
||||
self.payload.write_payload(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -88,12 +89,67 @@ impl Writeable for Deposit {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use hex_literal::hex;
|
||||
use wormhole_io::WriteableBytes;
|
||||
use wormhole_raw_vaas::cctp;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct AllYourBase {
|
||||
pub are: u16,
|
||||
pub belong: u32,
|
||||
pub to: u64,
|
||||
pub us: WriteableBytes,
|
||||
}
|
||||
|
||||
impl TypePrefixedPayload for AllYourBase {
|
||||
const TYPE: Option<u8> = Some(69);
|
||||
}
|
||||
|
||||
impl Readable for AllYourBase {
|
||||
const SIZE: Option<usize> = None;
|
||||
|
||||
fn read<R>(reader: &mut R) -> io::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
R: io::Read,
|
||||
{
|
||||
Ok(Self {
|
||||
are: Readable::read(reader)?,
|
||||
belong: Readable::read(reader)?,
|
||||
to: Readable::read(reader)?,
|
||||
us: Readable::read(reader)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for AllYourBase {
|
||||
fn written_size(&self) -> usize {
|
||||
2 + 4 + 8 + self.us.written_size()
|
||||
}
|
||||
|
||||
fn write<W>(&self, writer: &mut W) -> std::io::Result<()>
|
||||
where
|
||||
Self: Sized,
|
||||
W: std::io::Write,
|
||||
{
|
||||
self.are.write(writer)?;
|
||||
self.belong.write(writer)?;
|
||||
self.to.write(writer)?;
|
||||
self.us.write(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde() {
|
||||
let payload = AllYourBase {
|
||||
are: 42,
|
||||
belong: 1337,
|
||||
to: 9001,
|
||||
us: b"Beep boop".to_vec().into(),
|
||||
};
|
||||
|
||||
let deposit = Deposit {
|
||||
token_address: hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"),
|
||||
amount: U256::from(69420u64),
|
||||
|
@ -104,7 +160,7 @@ mod test {
|
|||
mint_recipient: hex!(
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||
),
|
||||
payload: b"All your base are belong to us.".to_vec(),
|
||||
payload: payload.clone(),
|
||||
};
|
||||
|
||||
let encoded = deposit.to_vec_payload();
|
||||
|
@ -120,12 +176,15 @@ mod test {
|
|||
cctp_nonce: parsed.cctp_nonce(),
|
||||
burn_source: parsed.burn_source(),
|
||||
mint_recipient: parsed.mint_recipient(),
|
||||
payload: parsed.payload().to_vec(),
|
||||
payload,
|
||||
};
|
||||
assert_eq!(deposit, expected);
|
||||
|
||||
// Check for other encoded parameters.
|
||||
assert_eq!(parsed.payload_len(), deposit.payload.len() as u16);
|
||||
assert_eq!(
|
||||
usize::from(parsed.payload_len()),
|
||||
deposit.payload.payload_written_size()
|
||||
);
|
||||
|
||||
// TODO: Recover by calling read_payload.
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ use anchor_spl::token;
|
|||
use wormhole_cctp_solana::{
|
||||
cctp::{message_transmitter_program, token_messenger_minter_program},
|
||||
utils::ExternalAccount,
|
||||
wormhole::core_bridge_program,
|
||||
wormhole::core_bridge_program::{
|
||||
self,
|
||||
sdk::io::{Readable, TypePrefixedPayload, Writeable},
|
||||
},
|
||||
};
|
||||
|
||||
/// Account context to invoke [transfer_tokens_with_payload].
|
||||
|
@ -144,6 +147,39 @@ pub struct TransferTokensWithPayloadArgs {
|
|||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WrappedVec(Vec<u8>);
|
||||
|
||||
impl Readable for WrappedVec {
|
||||
const SIZE: Option<usize> = None;
|
||||
|
||||
fn read<R>(reader: &mut R) -> std::io::Result<Self>
|
||||
where
|
||||
R: std::io::Read,
|
||||
{
|
||||
let mut out = vec![];
|
||||
reader.read_to_end(&mut out)?;
|
||||
Ok(Self(out))
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for WrappedVec {
|
||||
fn written_size(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn write<W>(&self, writer: &mut W) -> std::io::Result<()>
|
||||
where
|
||||
W: std::io::Write,
|
||||
{
|
||||
writer.write_all(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypePrefixedPayload for WrappedVec {
|
||||
const TYPE: Option<u8> = None;
|
||||
}
|
||||
|
||||
/// This instruction invokes both Wormhole Core Bridge and CCTP Token Messenger Minter programs to
|
||||
/// emit a Wormhole message associated with a CCTP message.
|
||||
///
|
||||
|
@ -231,7 +267,7 @@ pub fn transfer_tokens_with_payload(
|
|||
amount,
|
||||
mint_recipient,
|
||||
wormhole_message_nonce,
|
||||
payload,
|
||||
payload: WrappedVec(payload),
|
||||
},
|
||||
)?;
|
||||
|
||||
|
|
Loading…
Reference in New Issue