Skip to content

Commit 802152b

Browse files
author
bay
committed
faucet request with mwc-wallet
1 parent a92d7ac commit 802152b

File tree

8 files changed

+270
-38
lines changed

8 files changed

+270
-38
lines changed

api/src/owner.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ use crate::libwallet::{
4242
use crate::util::logger::LoggingConfig;
4343
use crate::util::secp::key::SecretKey;
4444
use crate::util::{from_hex, Mutex, ZeroingString};
45-
use libwallet::{wallet_lock, OwnershipProof, OwnershipProofValidation, RetrieveTxQueryArgs};
45+
use libwallet::{
46+
wallet_lock, Context, OwnershipProof, OwnershipProofValidation, RetrieveTxQueryArgs,
47+
};
4648
use mwc_wallet_util::mwc_util::secp::key::PublicKey;
4749
use mwc_wallet_util::mwc_util::static_secp_instance;
4850
use std::sync::atomic::{AtomicBool, Ordering};
@@ -930,6 +932,15 @@ where
930932
owner::issue_invoice_tx(&mut **w, keychain_mask, args, self.doctest_mode, 1)
931933
}
932934

935+
pub fn generate_invoice_slate(
936+
&self,
937+
keychain_mask: Option<&SecretKey>,
938+
amount: u64,
939+
) -> Result<(Slate, Context), Error> {
940+
wallet_lock!(self.wallet_inst, w);
941+
owner::generate_invoice_slate(&mut **w, keychain_mask, amount)
942+
}
943+
933944
/// Processes an invoice tranaction created by another party, essentially
934945
/// a `request for payment`. The incoming slate should contain a requested
935946
/// amount, an output created by the invoicer convering the amount, and

controller/src/command.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,119 @@ where
855855
Ok(())
856856
}
857857

858+
pub fn fauset_request<L, C, K>(
859+
owner_api: &mut Owner<L, C, K>,
860+
keychain_mask: Option<&SecretKey>,
861+
amount: u64,
862+
mqs_config: Option<MQSConfig>,
863+
) -> Result<(), Error>
864+
where
865+
L: WalletLCProvider<'static, C, K> + 'static,
866+
C: NodeClient + 'static,
867+
K: keychain::Keychain + 'static,
868+
{
869+
let wallet_inst = owner_api.wallet_inst.clone();
870+
let mut res_slate = Slate::blank(2, false);
871+
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
872+
let (slate, context) = api.generate_invoice_slate(m, amount)?;
873+
874+
if mwc_wallet_impls::adapters::get_mwcmqs_brocker().is_none() {
875+
//check to see if mqs_config is there, if not, return error
876+
let mqs_config_unwrapped;
877+
match mqs_config {
878+
Some(s) => {
879+
mqs_config_unwrapped = s;
880+
}
881+
None => {
882+
return Err(Error::MQSConfig(format!("NO MQS config!")));
883+
}
884+
}
885+
886+
let km = keychain_mask.map(|k| k.clone());
887+
888+
//start the listener finalize tx
889+
let _ = controller::init_start_mwcmqs_listener(
890+
wallet_inst.clone(),
891+
mqs_config_unwrapped,
892+
Arc::new(Mutex::new(km)),
893+
false,
894+
//None,
895+
)?;
896+
thread::sleep(Duration::from_millis(2000));
897+
}
898+
899+
let sender = create_sender(
900+
"mwcmqs",
901+
"xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU",
902+
&None,
903+
None,
904+
)?;
905+
906+
let (slatepack_secret, secp) = {
907+
wallet_lock!(api.wallet_inst, w);
908+
let keychain = w.keychain(keychain_mask)?;
909+
let slatepack_secret =
910+
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
911+
(slatepack_secret, keychain.secp().clone())
912+
};
913+
914+
res_slate = sender.send_tx(
915+
false,
916+
&slate,
917+
SlatePurpose::InvoiceInitial,
918+
&slatepack_secret,
919+
None,
920+
None,
921+
slate.height,
922+
&secp,
923+
)?;
924+
925+
{
926+
wallet_lock!(api.wallet_inst, w);
927+
let mut batch = w.batch(keychain_mask)?;
928+
// Participant id is 0 for mwc713 compatibility
929+
batch.save_private_context(slate.id.as_bytes(), 0, &context)?;
930+
batch.commit()?;
931+
}
932+
933+
Ok(())
934+
})?;
935+
936+
let km = match keychain_mask.as_ref() {
937+
None => None,
938+
Some(&m) => Some(m.to_owned()),
939+
};
940+
941+
controller::foreign_single_use(owner_api.wallet_inst.clone(), km, |api| {
942+
if let Err(e) = api.verify_slate_messages(&res_slate) {
943+
error!("Error validating participant messages: {}", e);
944+
return Err(Error::LibWallet(format!(
945+
"Unable to validate slate messages, {}",
946+
e
947+
)));
948+
}
949+
res_slate = api.finalize_invoice_tx(&res_slate)?;
950+
Ok(())
951+
})?;
952+
953+
// Posting
954+
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
955+
let result = api.post_tx(m, res_slate.tx_or_err()?, true);
956+
match result {
957+
Ok(_) => {
958+
info!("Transaction finished successfully.");
959+
Ok(())
960+
}
961+
Err(e) => {
962+
error!("Tx post error: {}", e);
963+
return Err(Error::LibWallet(format!("Unable to post slate, {}", e)));
964+
}
965+
}
966+
})?;
967+
968+
Ok(())
969+
}
970+
858971
/// Show slate pack and save it into the backup for historical purpose
859972
pub fn show_slatepack<L, C, K>(
860973
api: &mut Owner<L, C, K>,

doc/floonet_faucet.md

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,72 @@
1+
12
# MWC Floonet Faucet / MWC Testnet Faucet
23

3-
If you neeed some coins to test with MWC floonet, please be free to use the faucet that listen on MWC MQS address `xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU`.
4+
If you need some coins to test with the MWC Floonet network, feel free to use the faucet. It can send up to **5 MWC** per request on the Floonet testnet.
5+
6+
Testnet coins can be requested using `mwc-wallet` with the command:
47

5-
Faucet is running is mwc713 wallet, so we recommend to use mwc713 wallet to request the coins. Then you can transafer them to your QT wallet or mwc-wallet.
8+
```shell
9+
> mwc-wallet faucet_request --amount <amount>
10+
```
611

7-
You can download mwc713 from here: https://github.com/mwcproject/mwc713/releases
12+
You can download the `mwc-wallet` from the official releases page:
13+
👉 https://github.com/mwcproject/mwc-wallet/releases
814

9-
We are assuming that you already download, installed and provision your mwc713 wallet. Here are how you can request the coins. Please note, you can request maximun 5 MWC at a time.
15+
We assume you have already downloaded, installed, and initialized your `mwc-wallet`. Here’s how to request test coins.
16+
🔹 **Note:** The maximum amount you can request at once is **5 MWC**.
1017

11-
### How to request the coins
18+
---
1219

20+
### 💸 How to Request Coins
21+
22+
```shell
23+
> mwc-wallet --floonet faucet_request -a 1.2
24+
Password:
25+
20250705 19:02:06.812 WARN mwc_wallet_controller::controller - Starting MWCMQS Listener
26+
20250705 19:02:08.474 WARN mwc_wallet_impls::adapters::mwcmq -
27+
mwcmqs listener started for [xmh3yzhnBj4pxyo2N1upV6FYmqo5QpzM8YHv8HRMghTwm8ht5JR2] tid=[Mg1RKMoenGTULgK_XjBFC]
28+
slate [c0d202d4-0989-4a3b-a684-97514f84f25e] for [1.200000000] MWCs sent to [mwcmqs://xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU]
29+
Get invoice finalize slate [c0d202d4-0989-4a3b-a684-97514f84f25e] for [1.200000000] MWCs, processing...
30+
Invoice slate [c0d202d4-0989-4a3b-a684-97514f84f25e] for [1.200000000] MWCs was processed and sent back for posting.
31+
Command 'faucet_request' completed successfully
32+
33+
> mwc-wallet --floonet info
34+
Password:
35+
updater: the current_height is 1489662
36+
37+
____ Wallet Summary Info - Account 'default' as of height 1489662 ____
38+
39+
Confirmed Total | 4.200000000
40+
Awaiting Confirmation (< 10) | 3.000000000
41+
Awaiting Finalization | 11.200000000
42+
Locked by previous transaction | 0.000000000
43+
-------------------------------- | -------------
44+
Currently Spendable | 1.200000000
45+
46+
Command 'info' completed successfully
1347
```
14-
> mwc713 --floonet
15-
Using wallet configuration file at ......
16-
17-
Welcome to wallet713 for MWC v4.1.0
18-
19-
Unlock your existing wallet or type 'init' to initiate a new one
20-
Use 'help' to see available commands
21-
22-
ERROR: The wallet is locked. Please use 'unlock' first.
23-
wallet713>
24-
wallet713> unlock -p XXXXXXXXXX
25-
Your mwcmqs address: xmj6hXXXXXXXXXXXXX
26-
wallet713>
27-
wallet713> listen -s
28-
Starting mwcmqs listener...
29-
wallet713>
30-
mwcmqs listener started for [xmj6hTX7UKAXXXXXXXXXXXXXX] tid=[kbxsjQ2TAo0jjLsl8Ib_L]
31-
32-
wallet713> invoice 1.5 --to xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU
33-
slate [c7831053-80fb-4956-8abd-f2b270afc5ff] for [1.500000000] MWCs sent to [mwcmqs://xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU]
34-
slate [c7831053-80fb-4956-8abd-f2b270afc5ff] received back from [xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU] for [1.500000000] MWCs
35-
```
3648

37-
Please note, if faucet not used for a long time, it might take few minutes to wakeup and resync with a blockchain. If you invoice failed,
38-
please wait for 10 minutes and try again. If it is still offline, please ping any moderator at Discord( https://discord.gg/n5dZaty ) 'developers' channel.
49+
🕒 **Note:** If the faucet hasn't been used for a while, it may take a few minutes to wake up and resynchronize with the blockchain.
50+
If your invoice fails, please wait a couple of minutes and try again.
51+
52+
📣 If the faucet appears to be offline for an extended time, feel free to ping a moderator in the `#developers` channel on [Discord](https://discord.gg/n5dZaty).
3953

40-
### How to return the coin
54+
---
4155

42-
When you finish with your tests, please send the coins back to faucet.
56+
### 🔁 How to Return Coins
57+
58+
Once you’re done testing, please return the test coins to the faucet:
59+
60+
```shell
61+
> mwc-wallet --floonet send -m mwcmqs -d xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU <amount_to_send_back>
62+
Password:
63+
20250705 19:06:49.864 WARN mwc_wallet_controller::controller - Starting MWCMQS Listener
64+
20250705 19:06:52.488 WARN mwc_wallet_impls::adapters::mwcmq -
65+
mwcmqs listener started for [xmh3yzhnBj4pxyo2N1upV6FYmqo5QpzM8YHv8HRMghTwm8ht5JR2] tid=[RWSevePqTdwCumGfY99it]
66+
20250705 19:06:52.501 WARN mwc_wallet_controller::controller - Get back slate c0d202d4-0989-4a3b-a684-97514f84f25e. Because slate arrive too late, wallet not processing it
67+
slate [131a2cc5-cefa-4381-bdc5-e7e4b9abf788] for [1.100000000] MWCs sent to [mwcmqs://xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU]
68+
slate [131a2cc5-cefa-4381-bdc5-e7e4b9abf788] finalized successfully
69+
Command 'send' completed successfully
4370
```
44-
send 3.123 --to xmgEvZ4MCCGMJnRnNXKHBbHmSGWQchNr9uZpY5J1XXnsCFS45fsU -c 1
45-
```
71+
72+
Thank you for testing with MWC Floonet!

impls/src/adapters/mwcmq.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use mwc_wallet_libwallet::slatepack::SlatePurpose;
3131
use mwc_wallet_libwallet::swap::message::Message;
3232
use mwc_wallet_libwallet::swap::message::SwapMessage;
3333
use mwc_wallet_libwallet::{Slate, SlateVersion, VersionedSlate};
34+
use mwc_wallet_util::mwc_core::global;
3435
use mwc_wallet_util::mwc_util::secp::key::SecretKey;
3536
use mwc_wallet_util::mwc_util::secp::Secp256k1;
3637
use regex::Regex;
@@ -157,9 +158,11 @@ impl SlateSender for MwcMqsChannel {
157158
secp: &Secp256k1,
158159
) -> Result<Slate, Error> {
159160
if !send_tx {
160-
return Err(Error::MqsGenericError(
161-
"MWCMQS doesn't support invoice transactions".into(),
162-
));
161+
if global::is_mainnet() {
162+
return Err(Error::MqsGenericError(
163+
"MWCMQS doesn't support invoice transactions".into(),
164+
));
165+
}
163166
}
164167

165168
if let Some((mwcmqs_publisher, mwcmqs_subscriber)) = get_mwcmqs_brocker() {

libwallet/src/api_impl/owner.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,44 @@ where
691691
Ok(slate)
692692
}
693693

694+
/// Generate Floonet fouset Invoce slate
695+
pub fn generate_invoice_slate<'a, T: ?Sized, C, K>(
696+
w: &mut T,
697+
keychain_mask: Option<&SecretKey>,
698+
amount: u64,
699+
) -> Result<(Slate, Context), Error>
700+
where
701+
T: WalletBackend<'a, C, K>,
702+
C: NodeClient + 'a,
703+
K: Keychain + 'a,
704+
{
705+
if global::is_mainnet() {
706+
return Err(Error::FaucetRequestInvalidNetwork);
707+
}
708+
709+
let parent_key_id = w.parent_key_id();
710+
711+
let mut slate = tx::new_tx_slate(&mut *w, amount, 2, false, None, false)?;
712+
let chain_tip = slate.height; // it is fresh slate, height is a tip
713+
let context = tx::add_output_to_slate(
714+
&mut *w,
715+
keychain_mask,
716+
&mut slate,
717+
chain_tip,
718+
None,
719+
None,
720+
None,
721+
&parent_key_id,
722+
0,
723+
None,
724+
true,
725+
false,
726+
1,
727+
)?;
728+
729+
Ok((slate, context))
730+
}
731+
694732
/// Receive an invoice tx, essentially adding inputs to whatever
695733
/// output was specified
696734
/// Caller is responsible for wallet refresh

libwallet/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ pub enum Error {
366366
/// Invalid ownership proof
367367
#[error("Invalid ownership proof: {0}")]
368368
InvalidOwnershipProof(String),
369+
370+
/// Invalid network
371+
#[error("command 'faucet_request' works only with a floonet. Please restart your wallet with --floonet parameter.")]
372+
FaucetRequestInvalidNetwork,
369373
}
370374

371375
impl From<io::Error> for Error {

src/bin/mwc-wallet.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,4 +1053,12 @@ subcommands:
10531053
help: Proof record
10541054
short: p
10551055
long: proof
1056-
takes_value: true
1056+
takes_value: true
1057+
- faucet_request:
1058+
about: Request some coins from Floonet fauset
1059+
args:
1060+
- amount:
1061+
help: "Number of Floonet MWC coins to request. Maximum allowed number is 5 MWC, default: 3"
1062+
short: a
1063+
long: amount
1064+
takes_value: true

src/cmd/wallet_args.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,30 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
687687
}
688688
}
689689

690+
pub fn parse_faucet_request_args(args: &ArgMatches) -> Result<u64, ParseError> {
691+
let amount = parse_optional(args, "amount")?.unwrap_or("3.0".into());
692+
let amount = core::core::amount_from_hr_string(&amount);
693+
let amount = match amount {
694+
Ok(a) => {
695+
if a > 5000000000 {
696+
return Err(ParseError::ArgumentError(
697+
"Faucet single request amount is limited by 5 MWC".into(),
698+
));
699+
}
700+
a
701+
}
702+
Err(e) => {
703+
let msg = format!(
704+
"Could not parse amount as a number with optional decimal point. e={}",
705+
e
706+
);
707+
return Err(ParseError::ArgumentError(msg));
708+
}
709+
};
710+
711+
Ok(amount)
712+
}
713+
690714
pub fn parse_receive_unpack_args(args: &ArgMatches) -> Result<command::ReceiveArgs, ParseError> {
691715
// input file
692716
let input_file = match args.is_present("file") {
@@ -1939,6 +1963,10 @@ where
19391963
let proof = arg_parse!(parse_required(args, "proof"));
19401964
command::validate_ownership_proof(owner_api, km, proof)
19411965
}
1966+
("faucet_request", Some(args)) => {
1967+
let amount = arg_parse!(parse_faucet_request_args(&args));
1968+
command::fauset_request(owner_api, km, amount, Some(mqs_config.clone()))
1969+
}
19421970
(cmd, _) => {
19431971
return Err(Error::ArgumentError(format!(
19441972
"Unknown wallet command '{}', use 'mwc help wallet' for details",

0 commit comments

Comments
 (0)