Skip to content

Commit 06634b9

Browse files
committed
solana: broadcast transceiver info
1 parent 817c099 commit 06634b9

File tree

15 files changed

+498
-16
lines changed

15 files changed

+498
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,163 @@
1-
use crate::transceiver::Transceiver;
1+
use std::io;
2+
3+
use wormhole_io::{Readable, TypePrefixedPayload, Writeable};
4+
5+
#[cfg(feature = "anchor")]
6+
use anchor_lang::prelude::*;
7+
8+
use crate::{chain_id::ChainId, mode::Mode, transceiver::Transceiver};
29

310
#[derive(PartialEq, Eq, Clone, Debug)]
411
pub struct WormholeTransceiver {}
512

613
impl Transceiver for WormholeTransceiver {
714
const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10];
815
}
16+
17+
impl WormholeTransceiver {
18+
pub const INFO_PREFIX: [u8; 4] = [0x9c, 0x23, 0xbd, 0x3b];
19+
20+
pub const PEER_INFO_PREFIX: [u8; 4] = [0x18, 0xfc, 0x67, 0xc2];
21+
}
22+
23+
// * Transceiver info
24+
25+
#[derive(Debug, Clone, PartialEq, Eq)]
26+
pub struct WormholeTransceiverInfo {
27+
pub manager_address: [u8; 32],
28+
pub manager_mode: Mode,
29+
pub token_address: [u8; 32],
30+
pub token_decimals: u8,
31+
}
32+
33+
#[cfg(feature = "anchor")]
34+
impl AnchorDeserialize for WormholeTransceiverInfo {
35+
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
36+
Readable::read(reader)
37+
}
38+
}
39+
40+
#[cfg(feature = "anchor")]
41+
impl AnchorSerialize for WormholeTransceiverInfo {
42+
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
43+
Writeable::write(self, writer)
44+
}
45+
}
46+
47+
impl Readable for WormholeTransceiverInfo {
48+
const SIZE: Option<usize> = Some(32 + 1 + 32 + 1);
49+
50+
fn read<R>(reader: &mut R) -> std::io::Result<Self>
51+
where
52+
Self: Sized,
53+
R: std::io::Read,
54+
{
55+
let prefix = <[u8; 4]>::read(reader)?;
56+
if prefix != WormholeTransceiver::INFO_PREFIX {
57+
return Err(std::io::Error::new(
58+
std::io::ErrorKind::InvalidData,
59+
"Invalid prefix",
60+
));
61+
}
62+
63+
let manager_address = <[u8; 32]>::read(reader)?;
64+
let manager_mode = Mode::read(reader)?;
65+
let token_address = <[u8; 32]>::read(reader)?;
66+
let token_decimals = u8::read(reader)?;
67+
68+
Ok(WormholeTransceiverInfo {
69+
manager_address,
70+
manager_mode,
71+
token_address,
72+
token_decimals,
73+
})
74+
}
75+
}
76+
77+
impl Writeable for WormholeTransceiverInfo {
78+
fn written_size(&self) -> usize {
79+
WormholeTransceiverInfo::SIZE.unwrap()
80+
}
81+
82+
fn write<W>(&self, writer: &mut W) -> std::io::Result<()>
83+
where
84+
W: std::io::Write,
85+
{
86+
WormholeTransceiver::INFO_PREFIX.write(writer)?;
87+
self.manager_address.write(writer)?;
88+
self.manager_mode.write(writer)?;
89+
self.token_address.write(writer)?;
90+
self.token_decimals.write(writer)
91+
}
92+
}
93+
94+
impl TypePrefixedPayload for WormholeTransceiverInfo {
95+
const TYPE: Option<u8> = None;
96+
}
97+
98+
// * Transceiver registration
99+
100+
#[derive(Debug, Clone, PartialEq, Eq)]
101+
pub struct WormholeTransceiverRegistration {
102+
pub chain_id: ChainId,
103+
pub transceiver_address: [u8; 32],
104+
}
105+
106+
#[cfg(feature = "anchor")]
107+
impl AnchorDeserialize for WormholeTransceiverRegistration {
108+
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
109+
Readable::read(reader)
110+
}
111+
}
112+
113+
#[cfg(feature = "anchor")]
114+
impl AnchorSerialize for WormholeTransceiverRegistration {
115+
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
116+
Writeable::write(self, writer)
117+
}
118+
}
119+
120+
impl Readable for WormholeTransceiverRegistration {
121+
const SIZE: Option<usize> = Some(2 + 32);
122+
123+
fn read<R>(reader: &mut R) -> std::io::Result<Self>
124+
where
125+
Self: Sized,
126+
R: std::io::Read,
127+
{
128+
let prefix = <[u8; 4]>::read(reader)?;
129+
if prefix != WormholeTransceiver::PEER_INFO_PREFIX {
130+
return Err(std::io::Error::new(
131+
std::io::ErrorKind::InvalidData,
132+
"Invalid prefix",
133+
));
134+
}
135+
136+
let chain_id = ChainId::read(reader)?;
137+
let transceiver_address = <[u8; 32]>::read(reader)?;
138+
139+
Ok(WormholeTransceiverRegistration {
140+
chain_id,
141+
transceiver_address,
142+
})
143+
}
144+
}
145+
146+
impl Writeable for WormholeTransceiverRegistration {
147+
fn written_size(&self) -> usize {
148+
WormholeTransceiverRegistration::SIZE.unwrap()
149+
}
150+
151+
fn write<W>(&self, writer: &mut W) -> std::io::Result<()>
152+
where
153+
W: std::io::Write,
154+
{
155+
WormholeTransceiver::PEER_INFO_PREFIX.write(writer)?;
156+
self.chain_id.write(writer)?;
157+
self.transceiver_address.write(writer)
158+
}
159+
}
160+
161+
impl TypePrefixedPayload for WormholeTransceiverRegistration {
162+
const TYPE: Option<u8> = None;
163+
}

solana/programs/example-native-token-transfers/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,15 @@ pub mod example_native_token_transfers {
119119
) -> Result<()> {
120120
transceivers::wormhole::instructions::release_outbound(ctx, args)
121121
}
122+
123+
pub fn broadcast_wormhole_id(ctx: Context<BroadcastId>) -> Result<()> {
124+
transceivers::wormhole::instructions::broadcast_id(ctx)
125+
}
126+
127+
pub fn broadcast_wormhole_peer(
128+
ctx: Context<BroadcastPeer>,
129+
args: BroadcastPeerArgs,
130+
) -> Result<()> {
131+
transceivers::wormhole::instructions::broadcast_peer(ctx, args)
132+
}
122133
}

solana/programs/example-native-token-transfers/src/transceivers/wormhole/accounts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use anchor_lang::prelude::*;
33
use wormhole_anchor_sdk::wormhole;
44
use wormhole_io::TypePrefixedPayload;
55

6+
// TODO: should we add emitter in here too?
67
#[derive(Accounts)]
78
pub struct WormholeAccounts<'info> {
89
// wormhole stuff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use anchor_lang::prelude::*;
2+
use anchor_spl::token_interface;
3+
use ntt_messages::transceivers::wormhole::WormholeTransceiverInfo;
4+
5+
use crate::{config::*, transceivers::wormhole::accounts::*};
6+
7+
#[derive(Accounts)]
8+
pub struct BroadcastId<'info> {
9+
#[account(mut)]
10+
pub payer: Signer<'info>,
11+
12+
pub config: Account<'info, Config>,
13+
14+
#[account(
15+
address = config.mint,
16+
)]
17+
pub mint: InterfaceAccount<'info, token_interface::Mint>,
18+
19+
/// CHECK: initialized and written to by wormhole core bridge
20+
#[account(mut)]
21+
pub wormhole_message: Signer<'info>,
22+
23+
#[account(
24+
mut,
25+
seeds = [b"emitter"],
26+
bump
27+
)]
28+
pub emitter: UncheckedAccount<'info>,
29+
30+
pub wormhole: WormholeAccounts<'info>,
31+
}
32+
33+
pub fn broadcast_id(ctx: Context<BroadcastId>) -> Result<()> {
34+
let accs = ctx.accounts;
35+
let message = WormholeTransceiverInfo {
36+
manager_address: accs.config.to_account_info().owner.to_bytes(),
37+
manager_mode: accs.config.mode,
38+
token_address: accs.mint.to_account_info().key.to_bytes(),
39+
token_decimals: accs.mint.decimals,
40+
};
41+
42+
// TODO: should we send this as an unreliable message into a PDA?
43+
post_message(
44+
&accs.wormhole,
45+
accs.payer.to_account_info(),
46+
accs.wormhole_message.to_account_info(),
47+
accs.emitter.to_account_info(),
48+
ctx.bumps.emitter,
49+
&message,
50+
&[],
51+
)?;
52+
53+
Ok(())
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use anchor_lang::prelude::*;
2+
use ntt_messages::{chain_id::ChainId, transceivers::wormhole::WormholeTransceiverRegistration};
3+
4+
use crate::{
5+
config::*,
6+
transceivers::{accounts::peer::TransceiverPeer, wormhole::accounts::*},
7+
};
8+
9+
#[derive(Accounts)]
10+
#[instruction(args: BroadcastPeerArgs)]
11+
pub struct BroadcastPeer<'info> {
12+
#[account(mut)]
13+
pub payer: Signer<'info>,
14+
15+
pub config: Account<'info, Config>,
16+
17+
#[account(
18+
seeds = [TransceiverPeer::SEED_PREFIX, args.chain_id.to_be_bytes().as_ref()],
19+
bump
20+
)]
21+
pub peer: Account<'info, TransceiverPeer>,
22+
23+
/// CHECK: initialized and written to by wormhole core bridge
24+
#[account(mut)]
25+
pub wormhole_message: Signer<'info>,
26+
27+
#[account(
28+
mut,
29+
seeds = [b"emitter"],
30+
bump
31+
)]
32+
pub emitter: UncheckedAccount<'info>,
33+
34+
pub wormhole: WormholeAccounts<'info>,
35+
}
36+
37+
#[derive(AnchorSerialize, AnchorDeserialize)]
38+
pub struct BroadcastPeerArgs {
39+
pub chain_id: u16,
40+
}
41+
42+
pub fn broadcast_peer(ctx: Context<BroadcastPeer>, args: BroadcastPeerArgs) -> Result<()> {
43+
let accs = ctx.accounts;
44+
45+
let message = WormholeTransceiverRegistration {
46+
chain_id: ChainId { id: args.chain_id },
47+
transceiver_address: accs.peer.address,
48+
};
49+
50+
// TODO: should we send this as an unreliable message into a PDA?
51+
post_message(
52+
&accs.wormhole,
53+
accs.payer.to_account_info(),
54+
accs.wormhole_message.to_account_info(),
55+
accs.emitter.to_account_info(),
56+
ctx.bumps.emitter,
57+
&message,
58+
&[],
59+
)?;
60+
61+
Ok(())
62+
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
pub mod admin;
22
pub mod broadcast_id;
3+
pub mod broadcast_peer;
34
pub mod receive_message;
45
pub mod release_outbound;
56

67
pub use admin::*;
78
pub use broadcast_id::*;
9+
pub use broadcast_peer::*;
810
pub use receive_message::*;
911
pub use release_outbound::*;

0 commit comments

Comments
 (0)