Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion node/src/aggregates/instance_jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ async fn load_or_create_committee_instance_keypair(
// ------------------------------------------------------------------- answer

/// Answer a pending request with this committee node's instance key.
/// Skip requests already answered, no longer pending, or with spent inputs.
/// Skip requests already answered, no longer pending, with spent inputs or
/// whose amount does not cover the Gateway fee.
async fn answer_pegin_request(deps: &JobDeps, instance_id: Uuid) -> Result<Step> {
if deps.actor != Actor::Committee {
return Step::ignore("only committee nodes answer");
Expand Down
31 changes: 31 additions & 0 deletions node/src/utils/goat_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,17 @@ pub async fn read_pegin_request(
pegin_data.status
)));
}
let fee_sats = pegin_fee_sats(
pegin_data.pegin_amount_sats,
goat_client.gateway_get_min_pegin_fee_sats().await?,
goat_client.gateway_get_pegin_fee_rate().await?,
);
if fee_sats >= u128::from(pegin_data.pegin_amount_sats) {
bail!(SpecialError::InvalidPeginRequest(format!(
"pegin amount {} sats does not cover the Gateway fee of {fee_sats} sats",
pegin_data.pegin_amount_sats
)));
}
let network = get_network();
let user_change_address = Address::from_str(&pegin_data.user_change_addr)
.map_err(|e| SpecialError::InvalidPeginRequest(format!("invalid user_change_addr: {e}")))?
Expand Down Expand Up @@ -196,6 +207,13 @@ pub async fn read_pegin_request(
Ok((user_info, Amount::from_sat(pegin_data.pegin_amount_sats), pegin_data.committee_addresses))
}

/// The fee `Gateway.postPeginData` deducts; it reverts when the fee is not
/// below the amount.
fn pegin_fee_sats(amount_sats: u64, min_fee_sats: u64, fee_rate: u64) -> u128 {
const RATE_MULTIPLIER: u128 = 10_000;
u128::from(min_fee_sats) + u128::from(amount_sats) * u128::from(fee_rate) / RATE_MULTIPLIER
}

pub async fn read_instance_info_from_goat(
goat_client: &GOATClient,
instance_id: Uuid,
Expand Down Expand Up @@ -275,3 +293,16 @@ pub async fn get_graph_status(
.map_err(|_| anyhow!("unknown graph status: {}", graph.status))?,
))
}

#[cfg(test)]
mod fee_tests {
use super::pegin_fee_sats;

#[test]
fn the_pegin_fee_follows_the_gateway_formula() {
// Gateway defaults: 5000 sats plus 0.5%.
assert_eq!(pegin_fee_sats(1_000_000, 5_000, 50), 10_000);
assert_eq!(pegin_fee_sats(5_024, 5_000, 50), 5_025);
assert_eq!(pegin_fee_sats(u64::MAX, u64::MAX, 10_000), 2 * u128::from(u64::MAX));
}
}
Loading