Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions docs/api-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ curl "https://forest-explorer.chainsafe.dev/api/claim_token_all?address=0xAe9C4b

- Each address is subject to rate limiting to prevent abuse.
- This API only distributes Calibnet `tFIL` and `tUSDFC` tokens.
- ID address or its corresponding eth style `0xff…ID` address are restricted to
claim `tUSDFC` tokens.

## Rate Limits

Expand Down
67 changes: 16 additions & 51 deletions e2e/test_claim_token_api_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,19 +186,6 @@ export const TEST_SCENARIOS = {
faucet_info: FaucetTypes.CalibnetUSDFC,
address: TEST_ADDRESSES.T410_ADDRESS,
expectedStatus: STATUS_CODES.TOO_MANY_REQUESTS
},
{
name: 'CalibnetUSDFC (t0) - RATE LIMITED (within CalibnetUSDFC cooldown)',
faucet_info: FaucetTypes.CalibnetUSDFC,
address: TEST_ADDRESSES.T0_ADDRESS,
expectedStatus: STATUS_CODES.TOO_MANY_REQUESTS
},
// CalibnetUSDFC doesn't support the t1 format address
{
name: 'CalibnetUSDFC (ID) - RATE LIMITED (within CalibnetUSDFC cooldown)',
faucet_info: FaucetTypes.CalibnetUSDFC,
address: TEST_ADDRESSES.ETH_ID_CORRESPONDING,
expectedStatus: STATUS_CODES.TOO_MANY_REQUESTS
}
],

Expand Down Expand Up @@ -296,43 +283,21 @@ export const TEST_SCENARIOS = {
waitBefore: 0, // No wait needed, should be capped, already from the previous step
walletCapErrorResponse: true,
},

// TODO(forest-explorer): https://github.com/ChainSafe/forest-explorer/issues/335
// Token sent to the t0 and it's eth mapping address 0x
// are not accessible. Hence commenting out the following
// test cases.
// === CalibnetUSDFC ID Wallet (fresh wallet, 0 transactions) ===
// {
// name: 'CalibnetUSDFC (ID) - 1st SUCCESS (fresh wallet)',
// faucet_info: FaucetTypes.CalibnetUSDFC,
// address: TEST_ADDRESSES.ETH_ID_CORRESPONDING,
// expectedStatus: STATUS_CODES.SUCCESS,
// waitBefore: 65, // Wait for cooldown from the previous test group to expire
// walletCapErrorResponse: false,
// },
// {
// name: 'CalibnetUSDFC (ID) - 2nd SUCCESS (reaches cap)',
// faucet_info: FaucetTypes.CalibnetUSDFC,
// address: TEST_ADDRESSES.ETH_ID_CORRESPONDING,
// expectedStatus: STATUS_CODES.SUCCESS,
// waitBefore: 65, // Wait for cooldown from its own 1st transaction
// walletCapErrorResponse: false,
// },
// {
// name: 'CalibnetUSDFC (ID) - 3rd attempt (WALLET CAPPED)',
// faucet_info: FaucetTypes.CalibnetUSDFC,
// address: TEST_ADDRESSES.ETH_ID_CORRESPONDING,
// expectedStatus: STATUS_CODES.TOO_MANY_REQUESTS,
// waitBefore: 65, // Wait for cooldown from its own 2nd transaction
// walletCapErrorResponse: true,
// },
// {
// name: 'CalibnetUSDFC (t0) - check equivalence (WALLET CAPPED)',
// faucet_info: FaucetTypes.CalibnetUSDFC,
// address: TEST_ADDRESSES.T0_ADDRESS, // This is the same wallet as the ID address
// expectedStatus: STATUS_CODES.TOO_MANY_REQUESTS,
// waitBefore: 0, // No wait needed, should be capped already
// walletCapErrorResponse: true,
// },
{
name: 'CalibnetUSDFC (0xff...ID) - restricted address (RESTRICTED)',
faucet_info: FaucetTypes.CalibnetUSDFC,
address: TEST_ADDRESSES.ETH_ID_CORRESPONDING,
expectedStatus: STATUS_CODES.BAD_REQUEST,
waitBefore: 0, // No wait needed, should be restricted immediately.
walletCapErrorResponse: false,
},
{
name: 'CalibnetUSDFC (t0) - restricted address (RESTRICTED)',
faucet_info: FaucetTypes.CalibnetUSDFC,
address: TEST_ADDRESSES.T0_ADDRESS,
expectedStatus: STATUS_CODES.BAD_REQUEST,
waitBefore: 0, // No wait needed, should be restricted immediately.
walletCapErrorResponse: false,
},
]
};
18 changes: 15 additions & 3 deletions src/faucet/server_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ pub async fn claim_token(

let network = faucet_info.network();
set_current_network(network);
let recipient = parse_and_validate_address(&address, network)?;
let recipient = parse_and_validate_address(&address, faucet_info)?;
let rpc = Provider::from_network(network);
let from = faucet_address(faucet_info)
.await?
Expand Down Expand Up @@ -271,12 +271,24 @@ pub async fn claim_token_all(address: String) -> Result<Vec<ClaimResponse>, Serv
Ok(results)
}

#[cfg(feature = "ssr")]
fn is_address_restricted(address: &str, faucet_info: FaucetInfo) -> bool {
let address = address.trim().to_lowercase();
matches!(faucet_info, FaucetInfo::CalibnetUSDFC)
&& (address.starts_with("0xff000000000000000000000000") || address.starts_with("t0"))
}

#[cfg(feature = "ssr")]
fn parse_and_validate_address(
address: &str,
network: fvm_shared::address::Network,
faucet_info: FaucetInfo,
) -> Result<Address, ServerFnError> {
match crate::utils::address::parse_address(address, network) {
if is_address_restricted(address, faucet_info) {
log::error!("Restricted address: {}", address);
set_response_status(StatusCode::BAD_REQUEST);
return Err(ServerFnError::ServerError("Use of ID addresses or their corresponding Ethereum style 0xff...ID addresses is restricted when claiming tokens from the CalibnetUSDFC faucet.".to_string()));
}
match crate::utils::address::parse_address(address, faucet_info.network()) {
Ok(addr) => Ok(addr),
Err(e) => {
log::error!("Invalid address: {}", e);
Expand Down
Loading