Various token bridge and solitaire improvements
Derive message accounts from nonce and data vs sequence because sequence can lead to collision with parallel tx submission Change-Id: I82d5b3a3c7fd96b5a6c74933c773a32e1c58bdd4
This commit is contained in:
parent
c3fa835196
commit
5eb7d0b7d0
|
@ -57,6 +57,8 @@ dependencies = [
|
|||
"solana-sdk",
|
||||
"solitaire",
|
||||
"solitaire-client",
|
||||
"spl-token",
|
||||
"token-bridge",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -70,9 +72,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
|
@ -1146,7 +1148,7 @@ dependencies = [
|
|||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
@ -1304,7 +1306,7 @@ dependencies = [
|
|||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2 0.4.0",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
|
@ -1320,7 +1322,7 @@ dependencies = [
|
|||
"hyper",
|
||||
"log",
|
||||
"rustls",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"tokio-rustls",
|
||||
"webpki",
|
||||
]
|
||||
|
@ -1387,9 +1389,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
|
||||
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
|
@ -1466,9 +1468,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.96"
|
||||
version = "0.2.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -1611,9 +1613,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.11"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
|
||||
checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
|
@ -1780,9 +1782,9 @@ checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.7.2"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
dependencies = [
|
||||
"parking_lot 0.11.1",
|
||||
]
|
||||
|
@ -2275,7 +2277,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"tokio-rustls",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
|
@ -2722,7 +2724,7 @@ dependencies = [
|
|||
"solana-version",
|
||||
"solana-vote-program",
|
||||
"thiserror",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"tungstenite",
|
||||
"url",
|
||||
]
|
||||
|
@ -2787,7 +2789,7 @@ dependencies = [
|
|||
"solana-version",
|
||||
"spl-memo",
|
||||
"thiserror",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2875,7 +2877,7 @@ dependencies = [
|
|||
"solana-clap-utils",
|
||||
"solana-logger",
|
||||
"solana-version",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"url",
|
||||
]
|
||||
|
||||
|
@ -3426,6 +3428,22 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "token-bridge"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"bridge",
|
||||
"byteorder",
|
||||
"primitive-types",
|
||||
"rocksalt",
|
||||
"sha3",
|
||||
"solana-program",
|
||||
"solitaire",
|
||||
"solitaire-client",
|
||||
"spl-token",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.1.22"
|
||||
|
@ -3452,15 +3470,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.6.1"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975"
|
||||
checksum = "aea337f72e96efe29acc234d803a5981cd9a2b6ed21655cd7fc21cfe021e8ec7"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes 1.0.1",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio 0.7.11",
|
||||
"mio 0.7.13",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot 0.11.1",
|
||||
|
@ -3560,7 +3578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
|
@ -3661,7 +3679,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tokio 1.6.1",
|
||||
"tokio 1.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -9,7 +9,8 @@ crate-type = ["cdylib", "lib"]
|
|||
name = "bridge"
|
||||
|
||||
[features]
|
||||
no-entrypoint = ["solitaire/no-entrypoint", "solitaire-client"]
|
||||
no-entrypoint = ["solitaire/no-entrypoint"]
|
||||
client = ["solitaire-client"]
|
||||
no-idl = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
|
|
@ -12,8 +12,10 @@ use solitaire::{
|
|||
AccountState,
|
||||
Data,
|
||||
Derive,
|
||||
Info,
|
||||
};
|
||||
|
||||
pub type FeeCollector<'a> = Derive<Info<'a>, "fee_collector">;
|
||||
pub type Bridge<'a, const State: AccountState> = Derive<Data<'a, BridgeData, { State }>, "Bridge">;
|
||||
|
||||
pub type GuardianSet<'b, const State: AccountState> = Data<'b, types::GuardianSetData, { State }>;
|
||||
|
@ -30,6 +32,24 @@ impl<'b, const State: AccountState> Seeded<&GuardianSetDerivationData>
|
|||
}
|
||||
}
|
||||
|
||||
pub type Claim<'b, const State: AccountState> = Data<'b, types::ClaimData, { State }>;
|
||||
|
||||
pub struct ClaimDerivationData {
|
||||
pub emitter_address: [u8; 32],
|
||||
pub emitter_chain: u16,
|
||||
pub sequence: u64,
|
||||
}
|
||||
|
||||
impl<'b, const State: AccountState> Seeded<&ClaimDerivationData> for Claim<'b, { State }> {
|
||||
fn seeds(data: &ClaimDerivationData) -> Vec<Vec<u8>> {
|
||||
return vec![
|
||||
data.emitter_address.to_vec(),
|
||||
data.emitter_chain.to_be_bytes().to_vec(),
|
||||
data.sequence.to_be_bytes().to_vec(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
pub type SignatureSet<'b, const State: AccountState> = Data<'b, types::SignatureSet, { State }>;
|
||||
|
||||
pub struct SignaturesSetDerivationData {
|
||||
|
@ -48,15 +68,21 @@ pub type Message<'b, const State: AccountState> = Data<'b, PostedMessage, { Stat
|
|||
|
||||
pub struct MessageDerivationData {
|
||||
pub emitter_key: [u8; 32],
|
||||
pub sequence: u64,
|
||||
pub emitter_chain: u16,
|
||||
pub nonce: u32,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'b, const State: AccountState> Seeded<&MessageDerivationData> for Message<'b, { State }> {
|
||||
fn seeds(data: &MessageDerivationData) -> Vec<Vec<u8>> {
|
||||
vec![
|
||||
let mut seeds = vec![
|
||||
data.emitter_key.to_vec(),
|
||||
data.sequence.to_be_bytes().to_vec(),
|
||||
]
|
||||
data.emitter_chain.to_be_bytes().to_vec(),
|
||||
data.nonce.to_be_bytes().to_vec(),
|
||||
];
|
||||
seeds.append(&mut data.payload.chunks(32).map(|v| v.to_vec()).collect());
|
||||
|
||||
seeds
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
accounts::{
|
||||
Bridge,
|
||||
FeeCollector,
|
||||
Message,
|
||||
MessageDerivationData,
|
||||
Sequence,
|
||||
|
@ -28,15 +29,6 @@ use solitaire::{
|
|||
|
||||
type UninitializedMessage<'b> = Message<'b, { AccountState::Uninitialized }>;
|
||||
|
||||
impl<'a> From<&PostMessage<'a>> for MessageDerivationData {
|
||||
fn from(accs: &PostMessage<'a>) -> Self {
|
||||
MessageDerivationData {
|
||||
emitter_key: accs.emitter.key.to_bytes(),
|
||||
sequence: accs.sequence.sequence,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&PostMessage<'a>> for SequenceDerivationData<'a> {
|
||||
fn from(accs: &PostMessage<'a>) -> Self {
|
||||
SequenceDerivationData {
|
||||
|
@ -45,12 +37,9 @@ impl<'a> From<&PostMessage<'a>> for SequenceDerivationData<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type FeeAccount<'a> = Derive<Info<'a>, "Fees">;
|
||||
|
||||
#[derive(FromAccounts)]
|
||||
pub struct PostMessage<'b> {
|
||||
pub bridge: Bridge<'b, { AccountState::Initialized }>,
|
||||
pub fee_vault: FeeAccount<'b>,
|
||||
|
||||
/// Account to store the posted message
|
||||
pub message: UninitializedMessage<'b>,
|
||||
|
@ -65,17 +54,13 @@ pub struct PostMessage<'b> {
|
|||
pub payer: Signer<Info<'b>>,
|
||||
|
||||
/// Account to collect tx fee
|
||||
pub fee_collector: Derive<Info<'b>, "fee_collector">,
|
||||
|
||||
/// Instruction reflection account (special sysvar)
|
||||
pub instruction_acc: Info<'b>,
|
||||
pub fee_collector: FeeCollector<'b>,
|
||||
|
||||
pub clock: Sysvar<'b, Clock>,
|
||||
}
|
||||
|
||||
impl<'b> InstructionContext<'b> for PostMessage<'b> {
|
||||
fn verify(&self, program_id: &Pubkey) -> Result<()> {
|
||||
self.message.verify_derivation(program_id, &self.into())?;
|
||||
self.sequence.verify_derivation(program_id, &self.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -87,8 +72,6 @@ pub struct PostMessageData {
|
|||
pub nonce: u32,
|
||||
/// message payload
|
||||
pub payload: Vec<u8>,
|
||||
/// Emitter address
|
||||
pub emitter: Pubkey,
|
||||
}
|
||||
|
||||
pub fn post_message(
|
||||
|
@ -96,6 +79,15 @@ pub fn post_message(
|
|||
accs: &mut PostMessage,
|
||||
data: PostMessageData,
|
||||
) -> Result<()> {
|
||||
let msg_derivation = MessageDerivationData {
|
||||
emitter_key: accs.emitter.key.to_bytes(),
|
||||
emitter_chain: 1,
|
||||
nonce: data.nonce,
|
||||
payload: data.payload.clone(),
|
||||
};
|
||||
accs.message
|
||||
.verify_derivation(ctx.program_id, &msg_derivation)?;
|
||||
|
||||
// Fee handling
|
||||
let fee = transfer_fee();
|
||||
if accs
|
||||
|
@ -115,18 +107,18 @@ pub fn post_message(
|
|||
.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
|
||||
}
|
||||
|
||||
// Create message account
|
||||
accs.message
|
||||
.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
|
||||
|
||||
// Initialize transfer
|
||||
accs.message.submission_time = accs.clock.unix_timestamp as u32;
|
||||
accs.message.emitter_chain = 1;
|
||||
accs.message.emitter_address = accs.emitter.key.to_bytes();
|
||||
accs.message.nonce = data.nonce;
|
||||
accs.message.payload = data.payload.clone();
|
||||
accs.message.payload = data.payload;
|
||||
accs.message.sequence = accs.sequence.sequence;
|
||||
|
||||
// Create message account
|
||||
accs.message
|
||||
.create(&msg_derivation, ctx, accs.payer.key, Exempt)?;
|
||||
|
||||
// Bump sequence number
|
||||
accs.sequence.sequence += 1;
|
||||
|
||||
|
|
|
@ -49,15 +49,6 @@ impl<'a> From<&PostVAA<'a>> for SignaturesSetDerivationData {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&PostVAAData> for MessageDerivationData {
|
||||
fn from(data: &PostVAAData) -> Self {
|
||||
MessageDerivationData {
|
||||
emitter_key: data.emitter_address,
|
||||
sequence: data.sequence,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PostVAAData> for GuardianSetDerivationData {
|
||||
fn from(data: &PostVAAData) -> Self {
|
||||
GuardianSetDerivationData {
|
||||
|
@ -131,8 +122,14 @@ pub struct PostVAAData {
|
|||
}
|
||||
|
||||
pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) -> Result<()> {
|
||||
let msg_derivation = MessageDerivationData {
|
||||
emitter_key: vaa.emitter_address,
|
||||
emitter_chain: vaa.emitter_chain,
|
||||
nonce: vaa.nonce,
|
||||
payload: vaa.payload.clone(),
|
||||
};
|
||||
accs.message
|
||||
.verify_derivation(ctx.program_id, &(&vaa).into())?;
|
||||
.verify_derivation(ctx.program_id, &msg_derivation)?;
|
||||
accs.guardian_set
|
||||
.verify_derivation(ctx.program_id, &(&vaa).into())?;
|
||||
// Verify any required invariants before we process the instruction.
|
||||
|
@ -166,14 +163,13 @@ pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) ->
|
|||
|
||||
// If the VAA originates from another chain we need to create the account and populate all fields
|
||||
if vaa.emitter_chain != 1 {
|
||||
accs.message
|
||||
.create(&(&vaa).into(), ctx, accs.payer.key, Exempt)?;
|
||||
|
||||
accs.message.nonce = vaa.nonce;
|
||||
accs.message.emitter_chain = vaa.emitter_chain;
|
||||
accs.message.emitter_address = vaa.emitter_address;
|
||||
accs.message.sequence = vaa.sequence;
|
||||
accs.message.payload = vaa.payload;
|
||||
accs.message
|
||||
.create(&msg_derivation, ctx, accs.payer.key, Exempt)?;
|
||||
}
|
||||
|
||||
// Store VAA data in associated message.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// #![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))]
|
||||
#![feature(const_generics)]
|
||||
#![allow(warnings)]
|
||||
|
||||
// Salt contains the framework definition, single file for now but to be extracted into a cargo
|
||||
// package as soon as possible.
|
||||
pub mod accounts;
|
||||
|
|
|
@ -22,9 +22,12 @@ use solitaire::{
|
|||
},
|
||||
SolitaireError,
|
||||
};
|
||||
use std::io::{
|
||||
Cursor,
|
||||
Read,
|
||||
use std::{
|
||||
io::{
|
||||
Cursor,
|
||||
Read,
|
||||
},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
|
@ -101,7 +104,7 @@ impl Owned for SignatureSet {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize, Clone)]
|
||||
pub struct PostedMessage {
|
||||
/// Header of the posted VAA
|
||||
pub vaa_version: u8,
|
||||
|
@ -133,7 +136,9 @@ pub struct PostedMessage {
|
|||
|
||||
impl Owned for PostedMessage {
|
||||
fn owner(&self) -> AccountOwner {
|
||||
AccountOwner::This
|
||||
AccountOwner::Other(
|
||||
Pubkey::from_str("96RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE").unwrap(),
|
||||
) // TODO key of the bridge
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::{
|
||||
accounts::{
|
||||
Claim,
|
||||
ClaimDerivationData,
|
||||
},
|
||||
types::{
|
||||
ClaimData,
|
||||
PostedMessage,
|
||||
|
@ -115,21 +119,13 @@ impl<'b, T: DeserializePayload> PayloadMessage<'b, T> {
|
|||
}
|
||||
}
|
||||
|
||||
data_wrapper!(Claim, ClaimData, AccountState::Uninitialized);
|
||||
|
||||
impl<'b, T: DeserializePayload> Seeded<&ClaimableVAA<'b, T>> for Claim<'b> {
|
||||
fn seeds(_accs: &ClaimableVAA<'b, T>) -> Vec<Vec<u8>> {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromAccounts)]
|
||||
pub struct ClaimableVAA<'b, T: DeserializePayload> {
|
||||
// Signed message for the transfer
|
||||
pub message: PayloadMessage<'b, T>, // TODO use bridge type here that does verifications
|
||||
|
||||
// Claim account to prevent double spending
|
||||
pub claim: Claim<'b>,
|
||||
pub claim: Claim<'b, { AccountState::Uninitialized }>,
|
||||
}
|
||||
|
||||
impl<'b, T: DeserializePayload> Deref for ClaimableVAA<'b, T> {
|
||||
|
@ -144,7 +140,14 @@ impl<'b, T: DeserializePayload> InstructionContext<'b> for ClaimableVAA<'b, T> {
|
|||
// Do the Posted Message verification
|
||||
|
||||
// Verify that the claim account is derived correctly
|
||||
self.claim.verify_derivation(program_id, self)?;
|
||||
self.claim.verify_derivation(
|
||||
program_id,
|
||||
&ClaimDerivationData {
|
||||
emitter_address: self.message.meta().emitter_address,
|
||||
emitter_chain: self.message.meta().emitter_chain,
|
||||
sequence: self.message.meta().sequence,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -160,7 +163,16 @@ impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> {
|
|||
return Err(VAAAlreadyExecuted.into());
|
||||
}
|
||||
|
||||
self.claim.create(self, ctx, payer, Exempt)?;
|
||||
self.claim.create(
|
||||
&ClaimDerivationData {
|
||||
emitter_address: self.message.meta().emitter_address,
|
||||
emitter_chain: self.message.meta().emitter_chain,
|
||||
sequence: self.message.meta().sequence,
|
||||
},
|
||||
ctx,
|
||||
payer,
|
||||
Exempt,
|
||||
)?;
|
||||
self.claim.claimed = true;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -81,6 +81,7 @@ macro_rules! solitaire {
|
|||
}
|
||||
|
||||
use instruction::solitaire;
|
||||
#[cfg(not(feature = "no-entrypoint"))]
|
||||
solana_program::entrypoint!(solitaire);
|
||||
}
|
||||
}
|
||||
|
@ -153,10 +154,14 @@ macro_rules! pack_type {
|
|||
|
||||
impl BorshDeserialize for $name {
|
||||
fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
|
||||
Ok($name(
|
||||
let acc = $name(
|
||||
solana_program::program_pack::Pack::unpack(buf)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?,
|
||||
))
|
||||
);
|
||||
// We need to clear the buf to show to Borsh that we've read all data
|
||||
*buf = &buf[..0];
|
||||
|
||||
Ok(acc)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ use borsh::{
|
|||
BorshSerialize,
|
||||
};
|
||||
use solana_program::{
|
||||
entrypoint::ProgramResult,
|
||||
instruction::Instruction,
|
||||
program::invoke_signed,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
@ -82,6 +84,10 @@ pub trait Seeded<I> {
|
|||
seeds
|
||||
}
|
||||
|
||||
fn self_bumped_seeds(&self, accs: I, program_id: &Pubkey) -> Vec<Vec<u8>> {
|
||||
Self::bumped_seeds(accs, program_id)
|
||||
}
|
||||
|
||||
fn verify_derivation<'a, 'b: 'a>(&'a self, program_id: &'a Pubkey, accs: I) -> Result<()>
|
||||
where
|
||||
Self: Keyed<'a, 'b>,
|
||||
|
@ -147,3 +153,15 @@ impl<'a, const Seed: &'static str, T> Seeded<Option<()>> for Derive<T, Seed> {
|
|||
vec![Seed.as_bytes().to_vec()]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invoke_seeded<I, T: Seeded<I>>(
|
||||
instruction: &Instruction,
|
||||
context: &ExecutionContext,
|
||||
seeded_acc: &T,
|
||||
accs: I,
|
||||
) -> ProgramResult {
|
||||
let seeds = seeded_acc.self_bumped_seeds(accs, context.program_id);
|
||||
let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
|
||||
let seed_slice = s.as_slice();
|
||||
invoke_signed(instruction, context.accounts, &[seed_slice])
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use proc_macro2::{
|
|||
use quote::{
|
||||
quote,
|
||||
quote_spanned,
|
||||
ToTokens,
|
||||
};
|
||||
use std::borrow::BorrowMut;
|
||||
use syn::{
|
||||
|
@ -162,9 +163,12 @@ fn generate_fields(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
|||
let recurse = fields.named.iter().map(|f| {
|
||||
// Field name, to assign to.
|
||||
let name = &f.ident;
|
||||
let name_string =
|
||||
format!("Peeling: {}", name.to_token_stream().to_string());
|
||||
let ty = &f.ty;
|
||||
|
||||
quote! {
|
||||
solana_program::msg!(#name_string);
|
||||
let #name: #ty = solitaire::Peel::peel(&mut solitaire::Context::new(
|
||||
pid,
|
||||
iter,
|
||||
|
|
|
@ -51,11 +51,11 @@ pub fn generate_to_instruction(
|
|||
|
||||
quote! {
|
||||
/// Solitaire-generated client-side #name representation
|
||||
#[cfg(feature = "no-entrypoint")]
|
||||
#[cfg(feature = "client")]
|
||||
#client_struct_decl
|
||||
|
||||
/// Solitaire-generatied ToInstruction implementation
|
||||
#[cfg(feature = "no-entrypoint")]
|
||||
#[cfg(feature = "client")]
|
||||
impl #impl_generics solitaire_client::ToInstruction for #client_struct_name {
|
||||
fn to_ix(
|
||||
self,
|
||||
|
|
|
@ -156,16 +156,18 @@ where
|
|||
{
|
||||
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
|
||||
if let AccEntry::Sysvar(k) = a {
|
||||
if Var::check_id(k) {
|
||||
Ok(vec![AccountMeta::new_readonly(k.clone(), false)])
|
||||
} else {
|
||||
Err(format!("{} does not point at sysvar {}", k, std::any::type_name::<Var>()).into())
|
||||
}
|
||||
if Var::check_id(k) {
|
||||
Ok(vec![AccountMeta::new_readonly(k.clone(), false)])
|
||||
} else {
|
||||
Err(format!(
|
||||
"{} does not point at sysvar {}",
|
||||
k,
|
||||
std::any::type_name::<Var>()
|
||||
)
|
||||
.into())
|
||||
}
|
||||
} else {
|
||||
Err(format!(
|
||||
"{} must be passed as Sysvar",
|
||||
std::any::type_name::<Self>()
|
||||
).into())
|
||||
Err(format!("{} must be passed as Sysvar", std::any::type_name::<Self>()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue