Align behaviour of persistent message fees

Change-Id: Ic9c6c40dbac2399e0eaf3a861dff33254a828a18
This commit is contained in:
Hendrik Hofstadt 2021-07-05 17:00:50 +02:00
parent 0f854dc08b
commit 7784e74725
13 changed files with 329 additions and 111 deletions

View File

@ -112,7 +112,9 @@ Module [32]byte = "Core"
Action uint16 = 3
Chain uint16
// Message fee in the native token
Fee uint64
Fee uint256
// Persistent message fee in the native token
FeePersistent uint256
```
TransferFees:
@ -124,7 +126,7 @@ Module [32]byte = "Core"
Action uint16 = 4
Chain uint16
// Amount being transferred (big-endian uint256)
Amount [32]uint8
Amount uint256
// Address of the recipient. Left-zero-padded if shorter than 32 bytes
To [32]uint8
```

View File

@ -79,6 +79,7 @@ fn command_deploy_bridge(
initial_guardians: Vec<[u8; 20]>,
guardian_expiration: u32,
message_fee: u64,
message_fee_persistent: u64,
) -> CommmandResult {
println!("Initializing Wormhole bridge {}", bridge);
@ -90,6 +91,7 @@ fn command_deploy_bridge(
*bridge,
config.owner.pubkey(),
message_fee,
message_fee_persistent,
guardian_expiration,
initial_guardians.as_slice(),
)
@ -122,12 +124,19 @@ fn command_post_message(
None, bridge,
))?;
let bridge_config = BridgeData::try_from_slice(bridge_config_account.data.as_slice())?;
println!("Message fee: {} lamports", bridge_config.config.fee);
let fee = {
if persist {
bridge_config.config.fee_persistent
} else {
bridge_config.config.fee
}
};
println!("Message fee: {} lamports", fee);
let transfer_ix = transfer(
&config.owner.pubkey(),
&FeeCollector::key(None, bridge),
bridge_config.config.fee,
fee,
);
let (_, ix) = bridge::instructions::post_message(
*bridge,
@ -237,6 +246,15 @@ fn main() {
.index(4)
.required(true)
.help("Initial message posting fee"),
)
.arg(
Arg::with_name("message_fee_persistent")
.validator(is_u64)
.value_name("MESSAGE_FEE_PERSISTENT")
.takes_value(true)
.index(5)
.required(true)
.help("Initial persistent message posting fee"),
),
)
.subcommand(
@ -315,6 +333,7 @@ fn main() {
let guardian_expiration: u32 =
value_of(arg_matches, "guardian_set_expiration").unwrap();
let msg_fee: u64 = value_of(arg_matches, "message_fee").unwrap();
let msg_fee_persistent: u64 = value_of(arg_matches, "message_fee_persistent").unwrap();
let mut guardian = [0u8; 20];
guardian.copy_from_slice(&initial_data);
@ -324,6 +343,7 @@ fn main() {
vec![guardian],
guardian_expiration,
msg_fee,
msg_fee_persistent,
)
}
("post-message", Some(arg_matches)) => {

View File

@ -170,8 +170,8 @@ pub struct SetFeesData {}
pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> {
accs.vaa.claim(ctx, accs.payer.key)?;
// Set expiration time for the old set
accs.bridge.config.fee = accs.vaa.fee;
accs.bridge.config.fee = accs.vaa.fee.as_u64();
accs.bridge.config.fee_persistent = accs.vaa.persisted_fee.as_u64();
Ok(())
}

View File

@ -37,6 +37,9 @@ pub struct InitializeData {
/// Amount of lamports that needs to be paid to the protocol to post a message
pub fee: u64,
/// Amount of lamports that needs to be paid to the protocol to post a message
pub fee_persistent: u64,
/// Initial Guardian Set
pub initial_guardians: Vec<[u8; 20]>,
}
@ -71,6 +74,7 @@ pub fn initialize(
accs.bridge.config = BridgeConfig {
guardian_set_expiration_time: data.guardian_set_expiration_time,
fee: data.fee,
fee_persistent: data.fee_persistent,
};
// Initialize the fee collector account so it's rent exempt and will keep funds

View File

@ -96,6 +96,13 @@ pub fn post_message(
accs.message
.verify_derivation(ctx.program_id, &msg_derivation)?;
let fee = {
if data.persist {
accs.bridge.config.fee_persistent
} else {
accs.bridge.config.fee
}
};
// Fee handling, checking previously known balance allows us to not care who is the payer of
// this submission.
if accs
@ -103,11 +110,11 @@ pub fn post_message(
.lamports()
.checked_sub(accs.bridge.last_lamports)
.ok_or(MathOverflow)?
< accs.bridge.config.fee
< fee
{
trace!(
"Expected fee not found: fee, last_lamports, collector: {} {} {}",
accs.bridge.config.fee,
fee,
accs.bridge.last_lamports,
accs.fee_collector.lamports(),
);

View File

@ -29,9 +29,9 @@ use byteorder::{
};
use sha3::Digest;
use solana_program::{
msg,
program_error::ProgramError,
pubkey::Pubkey,
msg,
};
use solitaire::{
processors::seeded::Seeded,

View File

@ -44,6 +44,7 @@ pub fn initialize(
program_id: Pubkey,
payer: Pubkey,
fee: u64,
fee_persistent: u64,
guardian_set_expiration_time: u32,
initial_guardians: &[[u8; 20]],
) -> solitaire::Result<Instruction> {
@ -67,6 +68,7 @@ pub fn initialize(
data: crate::instruction::Instruction::Initialize(InitializeData {
initial_guardians: initial_guardians.to_vec(),
fee,
fee_persistent,
guardian_set_expiration_time,
})
.try_to_vec()?,

View File

@ -74,6 +74,8 @@ pub struct BridgeConfig {
/// Amount of lamports that needs to be paid to the protocol to post a message
pub fee: u64,
/// Amount of lamports that needs to be paid to the protocol to post a persistent message
pub fee_persistent: u64,
}
#[derive(Default, BorshSerialize, BorshDeserialize)]
@ -220,34 +222,6 @@ impl Owned for ClaimData {
}
}
pub struct GovernancePayloadUpgrade {
// Address of the new Implementation
pub new_contract: Pubkey,
}
impl DeserializePayload for GovernancePayloadUpgrade
where
Self: DeserializeGovernancePayload,
{
fn deserialize(buf: &mut &[u8]) -> Result<Self, SolitaireError> {
let mut c = Cursor::new(buf);
Self::check_governance_header(&mut c)?;
let mut addr = [0u8; 32];
c.read_exact(&mut addr)?;
Ok(GovernancePayloadUpgrade {
new_contract: Pubkey::new(&addr[..]),
})
}
}
impl DeserializeGovernancePayload for GovernancePayloadUpgrade {
const MODULE: &'static str = "CORE";
const ACTION: u8 = 2;
}
pub struct GovernancePayloadGuardianSetChange {
// New GuardianSetIndex
pub new_guardian_set_index: u32,
@ -262,7 +236,7 @@ impl SerializePayload for GovernancePayloadGuardianSetChange {
v.write_u32::<BigEndian>(self.new_guardian_set_index)?;
v.write_u8(self.new_guardian_set.len() as u8)?;
for key in self.new_guardian_set.iter() {
v.write(key);
v.write(key)?;
}
Ok(())
}
@ -297,15 +271,52 @@ impl DeserializeGovernancePayload for GovernancePayloadGuardianSetChange {
const ACTION: u8 = 1;
}
pub struct GovernancePayloadUpgrade {
// Address of the new Implementation
pub new_contract: Pubkey,
}
impl DeserializePayload for GovernancePayloadUpgrade
where
Self: DeserializeGovernancePayload,
{
fn deserialize(buf: &mut &[u8]) -> Result<Self, SolitaireError> {
let mut c = Cursor::new(buf);
Self::check_governance_header(&mut c)?;
let mut addr = [0u8; 32];
c.read_exact(&mut addr)?;
Ok(GovernancePayloadUpgrade {
new_contract: Pubkey::new(&addr[..]),
})
}
}
impl DeserializeGovernancePayload for GovernancePayloadUpgrade {
const MODULE: &'static str = "CORE";
const ACTION: u8 = 2;
}
pub struct GovernancePayloadSetMessageFee {
// New fee in lamports
pub fee: u64,
pub fee: U256,
// New fee for persisted messages in lamports
pub persisted_fee: U256,
}
impl SerializePayload for GovernancePayloadSetMessageFee {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
use byteorder::WriteBytesExt;
v.write_u64::<BigEndian>(self.fee)?;
let mut fee_data = [0u8; 32];
self.fee.to_big_endian(&mut fee_data);
v.write(&fee_data[..])?;
let mut fee_persistent_data = [0u8; 32];
self.persisted_fee.to_big_endian(&mut fee_persistent_data);
v.write(&fee_persistent_data[..])?;
Ok(())
}
}
@ -317,8 +328,18 @@ where
fn deserialize(buf: &mut &[u8]) -> Result<Self, SolitaireError> {
let mut c = Cursor::new(buf);
let fee = c.read_u64::<BigEndian>()?;
Ok(GovernancePayloadSetMessageFee { fee })
let mut fee_data: [u8; 32] = [0; 32];
c.read_exact(&mut fee_data)?;
let fee = U256::from_big_endian(&fee_data);
let mut fee_persisted_data: [u8; 32] = [0; 32];
c.read_exact(&mut fee_persisted_data)?;
let fee_persisted = U256::from_big_endian(&fee_persisted_data);
Ok(GovernancePayloadSetMessageFee {
fee,
persisted_fee: fee_persisted,
})
}
}

View File

@ -16,8 +16,8 @@ use secp256k1::{
};
use sha3::Digest;
use solana_client::{
rpc_client::RpcClient,
client_error::ClientError,
rpc_client::RpcClient,
rpc_config::RpcSendTransactionConfig,
};
use solana_program::{
@ -42,8 +42,8 @@ use solana_sdk::{
signature::{
read_keypair_file,
Keypair,
Signer,
Signature,
Signer,
},
transaction::Transaction,
};
@ -103,16 +103,15 @@ fn execute(
let mut transaction = Transaction::new_with_payer(instructions, Some(&payer.pubkey()));
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers.to_vec(), recent_blockhash);
client
.send_and_confirm_transaction_with_spinner_and_config(
&transaction,
CommitmentConfig::processed(),
RpcSendTransactionConfig {
skip_preflight: true,
preflight_commitment: None,
encoding: None,
},
)
client.send_and_confirm_transaction_with_spinner_and_config(
&transaction,
CommitmentConfig::processed(),
RpcSendTransactionConfig {
skip_preflight: true,
preflight_commitment: None,
encoding: None,
},
)
}
mod helpers {
@ -133,7 +132,10 @@ mod helpers {
}
/// Fetch account data, the loop is there to re-attempt until data is available.
pub fn get_account_data<T: BorshDeserialize>(client: &RpcClient, account: &Pubkey) -> Option<T> {
pub fn get_account_data<T: BorshDeserialize>(
client: &RpcClient,
account: &Pubkey,
) -> Option<T> {
for _ in 0..5 {
if let Ok(account) = client.get_account(account) {
return Some(T::try_from_slice(&account.data).unwrap());
@ -219,7 +221,12 @@ mod helpers {
(vaa, body, body_hash)
}
pub fn transfer(client: &RpcClient, from: &Keypair, to: &Pubkey, lamports: u64) -> Result<Signature, ClientError> {
pub fn transfer(
client: &RpcClient,
from: &Keypair,
to: &Pubkey,
lamports: u64,
) -> Result<Signature, ClientError> {
execute(
client,
from,
@ -257,14 +264,21 @@ mod helpers {
nonce: u32,
data: Vec<u8>,
fee: u64,
persist: bool,
) -> Result<Pubkey, ClientError> {
// Transfer money into the fee collector as it needs a balance/must exist.
let fee_collector = FeeCollector::<'_>::key(None, program);
// Capture the resulting message, later functions will need this.
let (message_key, instruction) =
instructions::post_message(*program, payer.pubkey(), emitter.pubkey(), nonce, data)
.unwrap();
let (message_key, instruction) = instructions::post_message(
*program,
payer.pubkey(),
emitter.pubkey(),
nonce,
data,
persist,
)
.unwrap();
execute(
client,
@ -317,7 +331,12 @@ mod helpers {
Ok(())
}
pub fn post_vaa(client: &RpcClient, program: &Pubkey, payer: &Keypair, vaa: PostVAAData) -> Result<Signature, ClientError> {
pub fn post_vaa(
client: &RpcClient,
program: &Pubkey,
payer: &Keypair,
vaa: PostVAAData,
) -> Result<Signature, ClientError> {
execute(
client,
payer,

View File

@ -1,7 +1,17 @@
#![allow(warnings)]
use borsh::BorshSerialize;
use secp256k1::Message;
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use secp256k1::{
Message,
PublicKey,
SecretKey,
};
use sha3::Digest;
use solana_client::rpc_client::RpcClient;
use solana_program::{
borsh::try_from_slice_unchecked,
@ -27,27 +37,17 @@ use solana_sdk::{
},
transaction::Transaction,
};
use byteorder::{
BigEndian,
WriteBytesExt,
};
use std::{
convert::TryInto,
io::{
Cursor,
Write,
},
time::{
Duration,
SystemTime,
},
};
use std::time::{
Duration,
SystemTime,
};
use hex_literal::hex;
use secp256k1::{
PublicKey,
SecretKey,
};
use sha3::Digest;
use bridge::{
accounts::GuardianSetDerivationData,
@ -66,14 +66,15 @@ use bridge::{
SerializePayload,
Signature,
};
use primitive_types::U256;
mod common;
const GOV_KEY: [u8; 64] = [
240, 133, 120, 113, 30, 67, 38, 184, 197, 72, 234, 99, 241, 21, 58, 225, 41, 157, 171, 44,
196, 163, 134, 236, 92, 148, 110, 68, 127, 114, 177, 0, 173, 253, 199, 9, 242, 142, 201,
174, 108, 197, 18, 102, 115, 0, 31, 205, 127, 188, 191, 56, 171, 228, 20, 247, 149, 170,
141, 231, 147, 88, 97, 199,
240, 133, 120, 113, 30, 67, 38, 184, 197, 72, 234, 99, 241, 21, 58, 225, 41, 157, 171, 44, 196,
163, 134, 236, 92, 148, 110, 68, 127, 114, 177, 0, 173, 253, 199, 9, 242, 142, 201, 174, 108,
197, 18, 102, 115, 0, 31, 205, 127, 188, 191, 56, 171, 228, 20, 247, 149, 170, 141, 231, 147,
88, 97, 199,
];
struct Context {
@ -109,7 +110,17 @@ fn test_bridge_messages(context: &mut Context) {
let emitter = Keypair::new();
// Post the message, publishing the data for guardian consumption.
let message_key = common::post_message(client, program, payer, &emitter, nonce, message.clone(), 10_000).unwrap();
let message_key = common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
// Emulate Guardian behaviour, verifying the data and publishing signatures/VAA.
let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 0);
@ -127,7 +138,17 @@ fn test_guardian_set_change(context: &mut Context) {
let emitter = Keypair::from_bytes(&GOV_KEY).unwrap();
// Post the message, publishing the data for guardian consumption.
let message_key = common::post_message(client, program, payer, &emitter, nonce, message.clone(), 10_000).unwrap();
let message_key = common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
// Emulate Guardian behaviour, verifying the data and publishing signatures/VAA.
let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 0);
@ -141,9 +162,21 @@ fn test_guardian_set_change(context: &mut Context) {
let message = GovernancePayloadGuardianSetChange {
new_guardian_set_index: 1,
new_guardian_set: new_public_keys.clone(),
}.try_to_vec().unwrap();
}
.try_to_vec()
.unwrap();
let message_key = common::post_message(client, program, payer, &emitter, nonce, message.clone(), 10_000).unwrap();
let message_key = common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 0);
common::verify_signatures(client, program, payer, body, body_hash, &context.secret, 0).unwrap();
common::post_vaa(client, program, payer, vaa).unwrap();
@ -157,11 +190,22 @@ fn test_guardian_set_change(context: &mut Context) {
0,
1,
1,
).unwrap();
)
.unwrap();
// Submit the message a second time with a new nonce.
let nonce = 12399;
let message_key = common::post_message(client, program, payer, &emitter, nonce, message.clone(), 10_000).unwrap();
let message_key = common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
context.public = new_public_keys;
context.secret = new_secret_keys;
@ -183,9 +227,21 @@ fn test_guardian_set_change_fails(context: &mut Context) {
let message = GovernancePayloadGuardianSetChange {
new_guardian_set_index: 2,
new_guardian_set: new_public_keys.clone(),
}.try_to_vec().unwrap();
}
.try_to_vec()
.unwrap();
let message_key = common::post_message(client, program, payer, &emitter, nonce, message.clone(), 10_000).unwrap();
let message_key = common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 1);
assert!(common::upgrade_guardian_set(
@ -197,7 +253,8 @@ fn test_guardian_set_change_fails(context: &mut Context) {
1,
2,
0,
).is_err());
)
.is_err());
}
fn test_set_fees(context: &mut Context) {
@ -206,9 +263,12 @@ fn test_set_fees(context: &mut Context) {
let emitter = Keypair::from_bytes(&GOV_KEY).unwrap();
let nonce = 12401;
let message = GovernancePayloadSetMessageFee { fee: 100 }
.try_to_vec()
.unwrap();
let message = GovernancePayloadSetMessageFee {
fee: U256::from(100),
persisted_fee: U256::from(100),
}
.try_to_vec()
.unwrap();
let message_key = common::post_message(
client,
@ -218,6 +278,7 @@ fn test_set_fees(context: &mut Context) {
nonce,
message.clone(),
10_000,
false,
)
.unwrap();
let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 1);
@ -229,13 +290,31 @@ fn test_set_fees(context: &mut Context) {
let emitter = Keypair::new();
let nonce = 12402;
let message = b"Fail to Pay".to_vec();
assert!(
common::post_message(client, program, payer, &emitter, nonce, message.clone(), 50).is_err()
);
assert!(common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
50,
false
)
.is_err());
// And succeeds with the new.
let emitter = Keypair::new();
let nonce = 12402;
let message = b"Fail to Pay".to_vec();
common::post_message(client, program, payer, &emitter, nonce, message.clone(), 100).unwrap();
common::post_message(
client,
program,
payer,
&emitter,
nonce,
message.clone(),
100,
false,
)
.unwrap();
}

View File

@ -44,7 +44,7 @@ spl-token mint "$token" 10000000000 "$account"
# Create the bridge contract at a known address
# OK to fail on subsequent attempts (already created).
retry client create-bridge "$bridge_address" "$initial_guardian" 86400 100
retry client create-bridge "$bridge_address" "$initial_guardian" 86400 100 200
# Let k8s startup probe succeed
nc -l -p 2000

View File

@ -12,7 +12,7 @@ use crate::msg::{
use crate::state::{
config, config_read, guardian_set_get, guardian_set_set, sequence_read, sequence_set,
vaa_archive_check, ConfigInfo, GovernancePacket, GuardianAddress, GuardianSetInfo,
GuardianSetUpgrade, ParsedVAA, TransferFee,
GuardianSetUpgrade, ParsedVAA, SetFee, TransferFee,
};
use k256::ecdsa::recoverable::Id as RecoverableId;
@ -30,7 +30,7 @@ const CHAIN_ID: u16 = 3;
// Lock assets fee amount and denomination
const FEE_AMOUNT: u128 = 10000;
const FEE_DENOMINATION: &str = "uluna";
pub const FEE_DENOMINATION: &str = "uluna";
pub fn init<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
@ -44,6 +44,7 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
guardian_set_index: 0,
guardian_set_expirity: msg.guardian_set_expirity,
fee: Coin::new(FEE_AMOUNT, FEE_DENOMINATION), // 0.01 Luna (or 10000 uluna) fee by default
fee_persisted: Coin::new(FEE_AMOUNT, FEE_DENOMINATION), // 0.01 Luna (or 10000 uluna) fee by default
};
config(&mut deps.storage).save(&state)?;
@ -103,9 +104,10 @@ fn handle_governance_payload<S: Storage, A: Api, Q: Querier>(
}
match gov_packet.action {
// 0 is reserved for upgrade / migration
1u8 => vaa_update_guardian_set(deps, env, &gov_packet.payload),
2u8 => handle_transfer_fee(deps, env, &gov_packet.payload),
// 1 is reserved for upgrade / migration
2u8 => vaa_update_guardian_set(deps, env, &gov_packet.payload),
3u8 => handle_set_fee(deps, env, &gov_packet.payload),
4u8 => handle_transfer_fee(deps, env, &gov_packet.payload),
_ => ContractError::InvalidVAAAction.std_err(),
}
}
@ -230,6 +232,32 @@ fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
})
}
pub fn handle_set_fee<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
data: &Vec<u8>,
) -> StdResult<HandleResponse> {
let set_fee_msg = SetFee::deserialize(&data)?;
// Save new fees
let mut state = config_read(&mut deps.storage).load()?;
state.fee = set_fee_msg.fee;
state.fee_persisted = set_fee_msg.fee_persistent;
config(&mut deps.storage).save(&state)?;
Ok(HandleResponse {
messages: vec![],
log: vec![
log("action", "fee_change"),
log("new_fee.amount", state.fee.amount),
log("new_fee.denom", state.fee.denom),
log("new_persisted_fee.amount", state.fee_persisted.amount),
log("new_persisted_fee.denom", state.fee_persisted.denom),
],
data: None,
})
}
pub fn handle_transfer_fee<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
@ -256,9 +284,16 @@ fn handle_post_message<S: Storage, A: Api, Q: Querier>(
persist: bool,
) -> StdResult<HandleResponse> {
let state = config_read(&deps.storage).load()?;
let fee = {
if persist {
state.fee
} else {
state.fee_persisted
}
};
// Check fee
if !has_coins(env.message.sent_funds.as_ref(), &state.fee) {
if !has_coins(env.message.sent_funds.as_ref(), &fee) {
return ContractError::FeeTooLow.std_err();
}

View File

@ -1,4 +1,4 @@
use schemars::JsonSchema;
use schemars::{JsonSchema, Set};
use serde::{Deserialize, Serialize};
use cosmwasm_std::{Binary, CanonicalAddr, Coin, HumanAddr, StdResult, Storage, Uint128};
@ -31,8 +31,10 @@ pub struct ConfigInfo {
pub gov_chain: u16,
pub gov_address: Vec<u8>,
// Asset locking fee
// Message sending fee
pub fee: Coin,
// Persisted message sending fee
pub fee_persisted: Coin,
}
// Validator Action Approval(VAA) data
@ -144,6 +146,7 @@ pub struct GuardianAddress {
pub bytes: Binary, // 20-byte addresses
}
use crate::contract::FEE_DENOMINATION;
#[cfg(test)]
use hex;
@ -263,7 +266,7 @@ impl GovernancePacket {
}
}
// action 1
// action 2
pub struct GuardianSetUpgrade {
pub new_guardian_set_index: u32,
pub new_guardian_set: GuardianSetInfo,
@ -303,7 +306,34 @@ impl GuardianSetUpgrade {
}
}
// action 2
// action 3
pub struct SetFee {
pub fee: Coin,
pub fee_persistent: Coin,
}
impl SetFee {
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
let data = data.as_slice();
let (_, amount) = data.get_u256(0);
let (_, amount_persistent) = data.get_u256(32);
let fee = Coin {
denom: String::from(FEE_DENOMINATION),
amount: Uint128(amount),
};
let fee_persistent = Coin {
denom: String::from(FEE_DENOMINATION),
amount: Uint128(amount_persistent),
};
Ok(SetFee {
fee,
fee_persistent,
})
}
}
// action 4
pub struct TransferFee {
pub amount: Coin,
pub recipient: CanonicalAddr,
@ -314,12 +344,11 @@ impl TransferFee {
let data = data.as_slice();
let recipient = data.get_address(0);
let amount = Uint128(data.get_u128_be(32));
let denom = match String::from_utf8(data[48..].to_vec()) {
Ok(s) => s,
Err(_) => return ContractError::InvalidVAA.std_err(),
let (_, amount) = data.get_u256(32);
let amount = Coin {
denom: String::from(FEE_DENOMINATION),
amount: Uint128(amount),
};
let amount = Coin { denom, amount };
Ok(TransferFee { amount, recipient })
}
}