Skip to main content

iota_faucet/faucet/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5mod simple_faucet;
6mod write_ahead_log;
7
8use std::{net::Ipv4Addr, path::PathBuf, sync::Arc};
9
10use async_trait::async_trait;
11use clap::Parser;
12use iota_sdk_types::{Address, ObjectId, TransactionDigest};
13use serde::{Deserialize, Serialize};
14use uuid::Uuid;
15
16pub use self::simple_faucet::SimpleFaucet;
17use crate::FaucetError;
18
19#[derive(Serialize, Deserialize, Debug, Clone)]
20pub struct FaucetReceipt {
21    pub sent: Vec<CoinInfo>,
22}
23
24#[derive(Serialize, Deserialize, Debug, Clone)]
25pub struct BatchFaucetReceipt {
26    pub task: String,
27}
28
29#[derive(Serialize, Deserialize, Debug, Clone)]
30#[serde(rename_all = "camelCase")]
31pub struct CoinInfo {
32    pub amount: u64,
33    pub id: ObjectId,
34    pub transfer_tx_digest: TransactionDigest,
35}
36
37#[derive(Serialize, Deserialize, Debug, Clone)]
38pub struct BatchSendStatus {
39    pub status: BatchSendStatusType,
40    pub transferred_gas_objects: Option<FaucetReceipt>,
41}
42
43#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
44#[serde(rename_all = "UPPERCASE")]
45pub enum BatchSendStatusType {
46    INPROGRESS,
47    SUCCEEDED,
48    DISCARDED,
49}
50
51pub struct AppState<F = Arc<SimpleFaucet>> {
52    pub faucet: F,
53    pub config: FaucetConfig,
54}
55
56impl<F> AppState<F> {
57    pub fn new(faucet: F, config: FaucetConfig) -> Self {
58        Self { faucet, config }
59    }
60}
61
62#[async_trait]
63pub trait Faucet {
64    /// Send `Coin<IOTA>` of the specified amount to the recipient
65    async fn send(
66        &self,
67        id: Uuid,
68        recipient: Address,
69        amounts: &[u64],
70    ) -> Result<FaucetReceipt, FaucetError>;
71
72    /// Send `Coin<IOTA>` of the specified amount to the recipient in a batch
73    /// request
74    async fn batch_send(
75        &self,
76        id: Uuid,
77        recipient: Address,
78        amounts: &[u64],
79    ) -> Result<BatchFaucetReceipt, FaucetError>;
80
81    /// Get the status of a batch_send request
82    async fn get_batch_send_status(&self, task_id: Uuid) -> Result<BatchSendStatus, FaucetError>;
83
84    /// Apply rate limiting
85    async fn rate_limit(&self, recipient: Address) -> Result<(), FaucetError>;
86}
87
88pub const DEFAULT_AMOUNT: u64 = 1_000_000_000;
89pub const DEFAULT_NUM_OF_COINS: usize = 1;
90
91#[derive(Parser, Clone)]
92#[command(
93    name = "IOTA Faucet",
94    about = "Faucet for requesting test tokens on IOTA"
95)]
96pub struct FaucetConfig {
97    #[arg(long, default_value_t = 5003)]
98    pub port: u16,
99
100    #[arg(long, default_value = "127.0.0.1")]
101    pub host_ip: Ipv4Addr,
102
103    #[arg(long, default_value_t = DEFAULT_AMOUNT)]
104    pub amount: u64,
105
106    #[arg(long, default_value_t = DEFAULT_NUM_OF_COINS)]
107    pub num_coins: usize,
108
109    #[arg(long, default_value_t = 10)]
110    pub request_buffer_size: usize,
111
112    #[arg(long, default_value_t = 10)]
113    pub max_request_per_second: u64,
114
115    #[arg(long, default_value_t = 60)]
116    pub wallet_client_timeout_secs: u64,
117
118    /// URL of the fullnode gRPC endpoint used for reading objects and
119    /// executing transactions.
120    #[arg(long, default_value = "http://127.0.0.1:8080")]
121    pub fullnode_grpc_url: String,
122
123    #[arg(long)]
124    pub write_ahead_log: PathBuf,
125
126    #[arg(long, default_value_t = 300)]
127    pub wal_retry_interval: u64,
128
129    #[arg(long, default_value_t = 10000)]
130    pub max_request_queue_length: u64,
131
132    #[arg(long, default_value_t = 500)]
133    pub batch_request_size: u64,
134
135    #[arg(long, default_value_t = 300)]
136    pub ttl_expiration: u64,
137
138    #[arg(long, action = clap::ArgAction::Set, default_value_t = false)]
139    pub batch_enabled: bool,
140
141    #[arg(long, default_value_t = false)]
142    pub enable_rate_limiting: bool,
143
144    #[arg(long, default_value_t = 12)]
145    pub max_requests_per_window: usize,
146
147    // default: 12 hours
148    #[arg(long, default_value_t = 43200)]
149    pub rate_window_secs: u64,
150}
151
152impl Default for FaucetConfig {
153    fn default() -> Self {
154        Self {
155            port: 5003,
156            host_ip: Ipv4Addr::new(127, 0, 0, 1),
157            amount: DEFAULT_AMOUNT,
158            num_coins: DEFAULT_NUM_OF_COINS,
159            request_buffer_size: 10,
160            max_request_per_second: 10,
161            wallet_client_timeout_secs: 60,
162            fullnode_grpc_url: "http://127.0.0.1:8080".to_string(),
163            write_ahead_log: Default::default(),
164            wal_retry_interval: 300,
165            max_request_queue_length: 10000,
166            batch_request_size: 500,
167            ttl_expiration: 300,
168            batch_enabled: false,
169            enable_rate_limiting: false,
170            max_requests_per_window: 12,
171            rate_window_secs: 12,
172        }
173    }
174}