mirror of
https://github.com/logos-co/nomos-node.git
synced 2026-08-27 09:31:10 +00:00
feat(wallet): add priority tip to support zone-sdk (#3116)
This commit is contained in:
@@ -965,6 +965,7 @@ pub(crate) fn channel_deposit_with_notes_sync(
|
||||
tx_builder,
|
||||
change_public_key,
|
||||
funding_public_keys,
|
||||
0,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
@@ -1465,6 +1466,7 @@ pub(crate) fn wallet_fund_tx_sync(
|
||||
request.tx_builder,
|
||||
request.change_public_key,
|
||||
request.funding_public_keys,
|
||||
request.priority_fee,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
@@ -1539,7 +1541,9 @@ pub type FfiWalletFundResult = FfiStatusResult<*mut c_char>;
|
||||
/// and submits the result via [`submit_signed_transaction`].
|
||||
///
|
||||
/// The request and response are JSON strings with the exact same schemas as
|
||||
/// the node's `POST /wallet/fund` HTTP request and response bodies.
|
||||
/// the node's `POST /wallet/fund` HTTP request and response bodies. The
|
||||
/// optional `priority_fee` field (default 0) is left as excess balance above
|
||||
/// the mandatory fee, paid to the block producer as the execution tip.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -7,7 +7,7 @@ use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
mantle::{
|
||||
GasCalculator as _, GasConstants, Note, NoteId, Op, Utxo,
|
||||
GasCalculator as _, GasConstants, Note, NoteId, Op, Utxo, Value,
|
||||
gas::{GasCost, GasOverflow},
|
||||
ledger::{BoundedUtxos, Inputs, Outputs},
|
||||
ops::{channel::withdraw::ChannelWithdrawOp, transfer::TransferOp},
|
||||
@@ -148,16 +148,20 @@ impl MantleTxBuilder {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// `priority_fee` is deliberately left unreturned: the resulting excess
|
||||
/// balance above the mandatory fee is the transaction's execution tip.
|
||||
pub fn return_change<G: GasConstants>(
|
||||
self,
|
||||
context: &MantleTxContext,
|
||||
change_pk: ZkPublicKey,
|
||||
priority_fee: Value,
|
||||
) -> Result<Option<Self>, TxBuilderError> {
|
||||
// Calculate the funding delta with a dummy change note to account for
|
||||
// the gas cost increase from adding the output
|
||||
let delta_with_change = self.with_dummy_change_note()?.funding_delta::<G>(context)?;
|
||||
let delta_target = i128::from(priority_fee);
|
||||
|
||||
match delta_with_change.cmp(&0) {
|
||||
match delta_with_change.cmp(&delta_target) {
|
||||
Ordering::Less | Ordering::Equal => {
|
||||
// NOTE: the `Equal` is important here since we
|
||||
// cannot create zero-valued outputs.
|
||||
@@ -170,16 +174,15 @@ impl MantleTxBuilder {
|
||||
// We have enough balance to cover the increase in cost from the change
|
||||
// note. Use return_change which properly accounts for the gas cost
|
||||
// increase from adding the change output.
|
||||
let change =
|
||||
u64::try_from(delta_with_change).expect("Positive delta must fit in u64");
|
||||
let change = u64::try_from(delta_with_change - delta_target)
|
||||
.expect("Positive delta must fit in u64");
|
||||
|
||||
let tx_with_change = self.add_ledger_output(Note {
|
||||
value: change,
|
||||
pk: change_pk,
|
||||
})?;
|
||||
|
||||
// Now the net balance should exactly equal the gas cost.
|
||||
assert_eq!(tx_with_change.funding_delta::<G>(context)?, 0);
|
||||
assert_eq!(tx_with_change.funding_delta::<G>(context)?, delta_target);
|
||||
|
||||
Ok(Some(tx_with_change))
|
||||
}
|
||||
@@ -495,7 +498,7 @@ mod tests {
|
||||
|
||||
// Add change note
|
||||
let builder = builder
|
||||
.return_change::<MainnetGasConstants>(&context, ZkPublicKey::zero())
|
||||
.return_change::<MainnetGasConstants>(&context, ZkPublicKey::zero(), 0)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ pub mod fund {
|
||||
use lb_core::{
|
||||
header::HeaderId,
|
||||
mantle::{
|
||||
OpProof,
|
||||
OpProof, Value,
|
||||
gas::GasCost,
|
||||
transactions::{MantleTx, builder::MantleTxBuilder},
|
||||
},
|
||||
@@ -162,6 +162,8 @@ pub mod fund {
|
||||
pub change_public_key: ZkPublicKey,
|
||||
pub funding_public_keys: Vec<ZkPublicKey>,
|
||||
pub max_tx_fee: GasCost,
|
||||
#[serde(default)]
|
||||
pub priority_fee: Value,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
||||
@@ -988,6 +988,7 @@ where
|
||||
tx_builder,
|
||||
req.change_public_key,
|
||||
req.funding_public_keys,
|
||||
0,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -1941,6 +1942,7 @@ pub mod wallet {
|
||||
req.tx_builder,
|
||||
req.change_public_key,
|
||||
req.funding_public_keys,
|
||||
req.priority_fee,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -46,7 +46,13 @@ where
|
||||
response: funded,
|
||||
} = self
|
||||
.api
|
||||
.fund_tx(None, tx_builder, config.funding_pk, vec![config.funding_pk])
|
||||
.fund_tx(
|
||||
None,
|
||||
tx_builder,
|
||||
config.funding_pk,
|
||||
vec![config.funding_pk],
|
||||
0,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| SdpWalletError::WalletApi(e.into()))?;
|
||||
|
||||
@@ -81,7 +87,13 @@ where
|
||||
response: funded,
|
||||
} = self
|
||||
.api
|
||||
.fund_tx(None, tx_builder, config.funding_pk, vec![config.funding_pk])
|
||||
.fund_tx(
|
||||
None,
|
||||
tx_builder,
|
||||
config.funding_pk,
|
||||
vec![config.funding_pk],
|
||||
0,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| SdpWalletError::WalletApi(e.into()))?;
|
||||
|
||||
@@ -116,7 +128,13 @@ where
|
||||
response: funded,
|
||||
} = self
|
||||
.api
|
||||
.fund_tx(None, tx_builder, config.funding_pk, vec![config.funding_pk])
|
||||
.fund_tx(
|
||||
None,
|
||||
tx_builder,
|
||||
config.funding_pk,
|
||||
vec![config.funding_pk],
|
||||
0,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| SdpWalletError::WalletApi(e.into()))?;
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ where
|
||||
tx_builder: MantleTxBuilder,
|
||||
change_pk: ZkPublicKey,
|
||||
funding_pks: Vec<ZkPublicKey>,
|
||||
priority_fee: Value,
|
||||
) -> Result<TipResponse<MantleTxBuilder>, WalletApiError> {
|
||||
let (resp_tx, rx) = oneshot::channel();
|
||||
|
||||
@@ -141,6 +142,7 @@ where
|
||||
tx_builder,
|
||||
change_pk,
|
||||
funding_pks,
|
||||
priority_fee,
|
||||
resp_tx,
|
||||
})
|
||||
.await?;
|
||||
@@ -194,7 +196,7 @@ where
|
||||
let mantle_tx_builder =
|
||||
MantleTxBuilder::new().add_ledger_output(Note::new(amount, recipient_pk))?;
|
||||
let funded_tx_builder = self
|
||||
.fund_tx(tip, mantle_tx_builder, change_pk, funding_pks)
|
||||
.fund_tx(tip, mantle_tx_builder, change_pk, funding_pks, 0)
|
||||
.await?;
|
||||
self.sign_tx(tip, funded_tx_builder.response).await
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ pub enum WalletMsg {
|
||||
tx_builder: MantleTxBuilder,
|
||||
change_pk: ZkPublicKey,
|
||||
funding_pks: Vec<ZkPublicKey>,
|
||||
priority_fee: Value,
|
||||
resp_tx: Sender<Result<TipResponse<MantleTxBuilder>, WalletServiceError>>,
|
||||
},
|
||||
BuildLeaderClaimTx {
|
||||
@@ -508,6 +509,7 @@ where
|
||||
tx_builder,
|
||||
change_pk,
|
||||
funding_pks,
|
||||
priority_fee,
|
||||
resp_tx,
|
||||
} => {
|
||||
let tip = match Self::msg_tip_or_latest(tip, cryptarchia).await {
|
||||
@@ -535,6 +537,7 @@ where
|
||||
change_pk,
|
||||
funding_pks,
|
||||
&context,
|
||||
priority_fee,
|
||||
) {
|
||||
Ok(funded) => funded,
|
||||
Err(err) => {
|
||||
@@ -1237,6 +1240,7 @@ where
|
||||
request.funding_pk,
|
||||
[request.funding_pk],
|
||||
&context,
|
||||
0,
|
||||
)?;
|
||||
|
||||
let funded_notes: Vec<NoteId> = funded_tx_builder.consumed_or_locked_notes().collect();
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
use lb_core::{
|
||||
header::HeaderId,
|
||||
mantle::{
|
||||
GasConstants, NoteId,
|
||||
GasConstants, NoteId, Value,
|
||||
ops::leader_claim::{VoucherCm, VoucherNullifier},
|
||||
transactions::{MantleTxBuilder, MantleTxContext},
|
||||
},
|
||||
@@ -361,7 +361,8 @@ impl<'u> ServiceState<'u> {
|
||||
}
|
||||
|
||||
/// Fund `tx_builder` from the wallet's UTXOs at `tip`, excluding notes
|
||||
/// already reserved for in-flight transactions.
|
||||
/// already reserved for in-flight transactions. `priority_fee` is left
|
||||
/// as excess balance above the mandatory fee (the execution tip).
|
||||
pub fn fund_tx<G: GasConstants>(
|
||||
&self,
|
||||
tip: HeaderId,
|
||||
@@ -369,6 +370,7 @@ impl<'u> ServiceState<'u> {
|
||||
change_pk: ZkPublicKey,
|
||||
funding_pks: impl IntoIterator<Item = impl Borrow<ZkPublicKey>>,
|
||||
context: &MantleTxContext,
|
||||
priority_fee: Value,
|
||||
) -> Result<MantleTxBuilder, WalletError> {
|
||||
self.wallet.fund_tx::<G>(
|
||||
tip,
|
||||
@@ -377,6 +379,7 @@ impl<'u> ServiceState<'u> {
|
||||
funding_pks,
|
||||
context,
|
||||
&self.pending_notes.note_ids(),
|
||||
priority_fee,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ Feature: Zone SDK
|
||||
| SEQ_B |
|
||||
| SEQ_C |
|
||||
When node "NODE_1" is at height 1 in 120 seconds
|
||||
And wallet "WALLET_1A" sends 100 notes of 1000 LGO to node "NODE_1" funding wallet as "FUNDING_TOPUP"
|
||||
And wallet "WALLET_1A" sends 100 notes of 1500 LGO to node "NODE_1" funding wallet as "FUNDING_TOPUP"
|
||||
And transaction "FUNDING_TOPUP" is included on node "NODE_1" in 180 seconds
|
||||
And I start zone sequencer "SEQ_A" with indexer
|
||||
When I stop zone sequencer "SEQ_A"
|
||||
@@ -518,7 +518,7 @@ Feature: Zone SDK
|
||||
| node_name | account_index | wallet_name | connected_to | sequencers |
|
||||
| NODE_1 | 1 | WALLET_1A | | SEQ_A, SEQ_B, SEQ_C |
|
||||
When node "NODE_1" is at height 1 in 120 seconds
|
||||
And wallet "WALLET_1A" sends 100 notes of 1000 LGO to node "NODE_1" funding wallet as "FUNDING_TOPUP"
|
||||
And wallet "WALLET_1A" sends 100 notes of 1500 LGO to node "NODE_1" funding wallet as "FUNDING_TOPUP"
|
||||
And transaction "FUNDING_TOPUP" is included on node "NODE_1" in 180 seconds
|
||||
And I start zone sequencer "SEQ_A" with indexer
|
||||
And sequencer "SEQ_A" submits zone config transaction:
|
||||
|
||||
@@ -31,6 +31,7 @@ pub fn fund_builder_from_wallet_source(
|
||||
[source.public_key()],
|
||||
context,
|
||||
&HashSet::new(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -195,7 +196,7 @@ fn evaluate_standard_funding_inputs(
|
||||
Ordering::Less => Ok(WalletFundingOutcome::NeedsMoreInputs),
|
||||
Ordering::Equal => Ok(WalletFundingOutcome::Funded(funded_builder)),
|
||||
Ordering::Greater => Ok(funded_builder
|
||||
.return_change::<MainnetGasConstants>(context, change_pk)?
|
||||
.return_change::<MainnetGasConstants>(context, change_pk, 0)?
|
||||
.map_or(
|
||||
WalletFundingOutcome::NeedsMoreInputs,
|
||||
WalletFundingOutcome::Funded,
|
||||
|
||||
@@ -1514,6 +1514,7 @@ async fn build_funded_custom_tx(
|
||||
let response = node_client
|
||||
.fund_tx(WalletFundRequestBody {
|
||||
tip: None,
|
||||
priority_fee: 0,
|
||||
tx_builder,
|
||||
change_public_key: funding_pk,
|
||||
funding_public_keys: vec![funding_pk],
|
||||
|
||||
@@ -208,6 +208,7 @@ async fn fund_via_node(
|
||||
change_public_key: funding_pk,
|
||||
funding_public_keys: vec![funding_pk],
|
||||
max_tx_fee: GasCost::new(u64::MAX),
|
||||
priority_fee: 0,
|
||||
})
|
||||
.await
|
||||
.map_err(|source| StepError::StepFail {
|
||||
|
||||
+97
-16
@@ -197,6 +197,9 @@ impl WalletState {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Funds the transaction so its excess balance is exactly
|
||||
/// `priority_fee` above the mandatory fee — the excess is the
|
||||
/// transaction's execution tip. `0` funds to the exact minimum.
|
||||
pub fn fund_tx<G: GasConstants>(
|
||||
&self,
|
||||
tx_builder: &MantleTxBuilder,
|
||||
@@ -204,6 +207,7 @@ impl WalletState {
|
||||
pks: impl IntoIterator<Item = impl Borrow<ZkPublicKey>>,
|
||||
context: &MantleTxContext,
|
||||
excluded_notes: &HashSet<NoteId>,
|
||||
priority_fee: Value,
|
||||
) -> Result<MantleTxBuilder, WalletError> {
|
||||
// Get all UTXOs owned by the provided PKs, excluding the following notes:
|
||||
// - Notes that are being consumed/locked by the tx
|
||||
@@ -223,15 +227,21 @@ impl WalletState {
|
||||
// Consume large valued notes first to ensure we converge.
|
||||
utxos.sort_by_key(|utxo| -i128::from(utxo.note.value));
|
||||
|
||||
// The funding target: the tx's excess balance over the mandatory fee
|
||||
// must end up exactly at `priority_fee` (the execution tip).
|
||||
let delta_target = i128::from(priority_fee);
|
||||
|
||||
// The transaction may already be funded before we add any of the
|
||||
// wallet's UTXOs, for example when it pays no fee or the caller already
|
||||
// supplied inputs. In that case we must not pull in an extra input (and
|
||||
// the change note it would require).
|
||||
match tx_builder.funding_delta::<G>(context)?.cmp(&0) {
|
||||
match tx_builder.funding_delta::<G>(context)?.cmp(&delta_target) {
|
||||
Ordering::Equal => return Ok(tx_builder.clone()),
|
||||
Ordering::Greater => {
|
||||
if let Some(tx_with_change) =
|
||||
tx_builder.clone().return_change::<G>(context, change_pk)?
|
||||
tx_builder
|
||||
.clone()
|
||||
.return_change::<G>(context, change_pk, priority_fee)?
|
||||
{
|
||||
return Ok(tx_with_change);
|
||||
}
|
||||
@@ -248,12 +258,13 @@ impl WalletState {
|
||||
|
||||
let funding_delta = funded_tx_builder.funding_delta::<G>(context)?;
|
||||
|
||||
match funding_delta.cmp(&0) {
|
||||
match funding_delta.cmp(&delta_target) {
|
||||
Ordering::Less => {
|
||||
// Insufficient funds, need more UTXO's.
|
||||
}
|
||||
Ordering::Equal => {
|
||||
// We can exactly pay the tx cost, no change note needed.
|
||||
// We can exactly pay the tx cost plus the tip, no change
|
||||
// note needed.
|
||||
return Ok(funded_tx_builder);
|
||||
}
|
||||
Ordering::Greater => {
|
||||
@@ -261,7 +272,7 @@ impl WalletState {
|
||||
// The change note will slightly increase the storage cost of the tx so there is
|
||||
// a chance that we will not be able to fund the tx with the change note.
|
||||
if let Some(tx_with_change) =
|
||||
funded_tx_builder.return_change::<G>(context, change_pk)?
|
||||
funded_tx_builder.return_change::<G>(context, change_pk, priority_fee)?
|
||||
{
|
||||
// We were able to fund the tx with change note added.
|
||||
return Ok(tx_with_change);
|
||||
@@ -703,6 +714,10 @@ where
|
||||
Ok(self.wallet_state_at(tip)?.balance(pk))
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::too_many_arguments,
|
||||
reason = "thin passthrough to `WalletState::fund_tx` plus the tip"
|
||||
)]
|
||||
pub fn fund_tx<G: GasConstants>(
|
||||
&self,
|
||||
tip: HeaderId,
|
||||
@@ -711,6 +726,7 @@ where
|
||||
funding_pks: impl IntoIterator<Item = impl Borrow<ZkPublicKey>>,
|
||||
context: &MantleTxContext,
|
||||
excluded_notes: &HashSet<NoteId>,
|
||||
priority_fee: Value,
|
||||
) -> Result<MantleTxBuilder, WalletError> {
|
||||
self.wallet_state_at(tip)?.fund_tx::<G>(
|
||||
tx_builder,
|
||||
@@ -718,6 +734,7 @@ where
|
||||
funding_pks,
|
||||
context,
|
||||
excluded_notes,
|
||||
priority_fee,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1248,7 +1265,7 @@ mod tests {
|
||||
|
||||
// Fund the transaction
|
||||
let funded_tx_builder = wallet_state
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new())
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -1279,6 +1296,64 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fund_tx_with_priority_fee() {
|
||||
let alice = pk(1);
|
||||
let utxo = Utxo::new(tx_hash(0), 0, Note::new(5000, alice));
|
||||
let ledger_state = LedgerState::from_utxos([utxo], &ledger_config());
|
||||
let wallet_state =
|
||||
WalletState::from_ledger(&HashMap::from_iter([(alice, 1)]), &ledger_state);
|
||||
|
||||
let context = MantleTxContext {
|
||||
gas_context: MantleTxGasContext::from_channels(
|
||||
&Channels::default(),
|
||||
GasPrices::new(1, 1),
|
||||
),
|
||||
leader_reward_amount: 0,
|
||||
};
|
||||
let tx_builder = MantleTxBuilder::new();
|
||||
let priority_fee = 200;
|
||||
|
||||
let funded_tx_builder = wallet_state
|
||||
.fund_tx::<Gas>(
|
||||
&tx_builder,
|
||||
alice,
|
||||
[alice],
|
||||
&context,
|
||||
&HashSet::new(),
|
||||
priority_fee,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The tip is left as excess balance above the mandatory fee.
|
||||
let gas_cost = funded_tx_builder
|
||||
.gas_cost::<Gas>(&context)
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(
|
||||
i128::from(gas_cost + priority_fee),
|
||||
funded_tx_builder.net_balance()
|
||||
);
|
||||
assert_eq!(
|
||||
i128::from(priority_fee),
|
||||
funded_tx_builder.funding_delta::<Gas>(&context).unwrap()
|
||||
);
|
||||
|
||||
// The change output shrank by exactly the tip.
|
||||
let funded_tx = funded_tx_builder.build().unwrap();
|
||||
if let Op::Transfer(transfer_op) = &funded_tx.ops()[funded_tx.ops().len() - 1] {
|
||||
assert_eq!(
|
||||
transfer_op.outputs,
|
||||
Outputs::new([Note {
|
||||
value: 5000 - gas_cost - priority_fee,
|
||||
pk: alice,
|
||||
}])
|
||||
);
|
||||
} else {
|
||||
panic!("last op must be a transfer")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fund_tx_no_fee_adds_no_input() {
|
||||
let alice = pk(1);
|
||||
@@ -1312,7 +1387,7 @@ mod tests {
|
||||
assert_eq!(0, tx_builder.funding_delta::<Gas>(&context).unwrap());
|
||||
|
||||
let funded_tx_builder = wallet_state
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new())
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0)
|
||||
.unwrap();
|
||||
|
||||
// No input was pulled in (an added input would push the net balance to
|
||||
@@ -1368,7 +1443,7 @@ mod tests {
|
||||
|
||||
// Fund the transaction
|
||||
let fund_attempt =
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new());
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0);
|
||||
|
||||
assert_eq!(
|
||||
fund_attempt.unwrap_err(),
|
||||
@@ -1397,7 +1472,7 @@ mod tests {
|
||||
|
||||
// Fund the transaction
|
||||
let fund_attempt =
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new());
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0);
|
||||
|
||||
assert_eq!(
|
||||
fund_attempt.unwrap_err(),
|
||||
@@ -1429,7 +1504,7 @@ mod tests {
|
||||
|
||||
// Fund the transaction
|
||||
let fund_attempt =
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new());
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0);
|
||||
|
||||
assert_eq!(
|
||||
fund_attempt.unwrap_err(),
|
||||
@@ -1462,7 +1537,7 @@ mod tests {
|
||||
|
||||
// Attempt to fund the transaction with Alice's notes.
|
||||
let fund_attempt =
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new());
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0);
|
||||
|
||||
assert_eq!(
|
||||
fund_attempt.unwrap_err(),
|
||||
@@ -1471,7 +1546,7 @@ mod tests {
|
||||
|
||||
// Fund the transaction with Bob's notes.
|
||||
wallet_state
|
||||
.fund_tx::<Gas>(&tx_builder, bob, [bob], &context, &HashSet::new())
|
||||
.fund_tx::<Gas>(&tx_builder, bob, [bob], &context, &HashSet::new(), 0)
|
||||
.unwrap(); // succesfully funded;
|
||||
}
|
||||
|
||||
@@ -1511,7 +1586,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let funded_tx_wo_change = wallet_state
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new())
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(); // successfully funded the tx
|
||||
@@ -1551,8 +1626,14 @@ mod tests {
|
||||
),
|
||||
);
|
||||
|
||||
let fund_attempt =
|
||||
wallet_state.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new());
|
||||
let fund_attempt = wallet_state.fund_tx::<Gas>(
|
||||
&tx_builder,
|
||||
alice,
|
||||
[alice],
|
||||
&context,
|
||||
&HashSet::new(),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
fund_attempt.unwrap_err(),
|
||||
@@ -1570,7 +1651,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let funded_tx_wo_change = wallet_state
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new())
|
||||
.fund_tx::<Gas>(&tx_builder, alice, [alice], &context, &HashSet::new(), 0)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(); // successfully funded the tx
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use lb_core::{
|
||||
mantle::{
|
||||
MantleTx, SignedMantleTx, Transaction as _,
|
||||
MantleTx, SignedMantleTx, Transaction as _, Value,
|
||||
channel::{ChannelState, SlotTimeframe, SlotTimeout},
|
||||
ops::{
|
||||
Op, OpProof,
|
||||
@@ -20,6 +20,14 @@ use lb_key_management_system_service::keys::{Ed25519Key, Ed25519Signature};
|
||||
use super::types::{Error, FundingConfig};
|
||||
use crate::adapter;
|
||||
|
||||
/// Execution tip paid on top of the mandatory fee when funding a transaction,
|
||||
/// buffering gas-price movement between funding and inclusion: in the current
|
||||
/// spec the base fee moves at most 12.5% per block, so this covers a few
|
||||
/// blocks of drift at current fee levels.
|
||||
///
|
||||
/// TODO: promote to [`FundingConfig`] if clients need to tune it.
|
||||
const PRIORITY_FEE: Value = 200;
|
||||
|
||||
/// Assemble the ops for a transaction, funding it from the node's wallet when
|
||||
/// a [`FundingConfig`] is present.
|
||||
///
|
||||
@@ -53,6 +61,7 @@ where
|
||||
change_public_key: funding.funding_pk,
|
||||
funding_public_keys: vec![funding.funding_pk],
|
||||
max_tx_fee: funding.max_tx_fee,
|
||||
priority_fee: PRIORITY_FEE,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| Error::Network(format!("funding failed: {e}")))?;
|
||||
|
||||
Reference in New Issue
Block a user