From 3c594c8b4a6d88837e01eec29c02ccbc7412ef50 Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 05:12:28 +0530 Subject: [PATCH 01/17] Add support for delegated address in forest-wallet --- src/message_pool/msgpool/msg_pool.rs | 10 +++- src/rpc/methods/eth.rs | 2 +- src/wallet/subcommands/wallet_cmd.rs | 83 ++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/message_pool/msgpool/msg_pool.rs b/src/message_pool/msgpool/msg_pool.rs index 48c3c9caa69f..cffd326a42ab 100644 --- a/src/message_pool/msgpool/msg_pool.rs +++ b/src/message_pool/msgpool/msg_pool.rs @@ -16,8 +16,9 @@ use crate::eth::is_valid_eth_tx_for_sending; use crate::libp2p::{NetworkMessage, PUBSUB_MSG_STR, Topic}; use crate::message::{ChainMessage, Message, SignedMessage, valid_for_block_inclusion}; use crate::networks::{ChainConfig, NEWEST_NETWORK_VERSION}; +use crate::rpc::eth::types::EthAddress; use crate::shim::{ - address::Address, + address::{Address, Protocol}, crypto::{Signature, SignatureType}, econ::TokenAmount, gas::{Gas, price_list_by_network_version}, @@ -265,6 +266,13 @@ where if to_vec(msg)?.len() > MAX_MESSAGE_SIZE { return Err(Error::MessageTooBig); } + // Reject delegated (f4) recipient if not a valid Eth address (avoids black-hole sends). + let to = msg.message().to(); + if to.protocol() == Protocol::Delegated && EthAddress::from_filecoin_address(&to).is_err() { + return Err(Error::Other(format!( + "message recipient {to} is a delegated address but not a valid Eth Address" + ))); + } valid_for_block_inclusion(msg.message(), Gas::new(0), NEWEST_NETWORK_VERSION)?; if msg.value() > *crate::shim::econ::TOTAL_FILECOIN { return Err(Error::MessageValueTooHigh); diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 13a0ae4ec3f5..7e1a7d17f5e2 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -1012,7 +1012,7 @@ async fn execute_tipset( )) } -fn is_eth_address(addr: &VmAddress) -> bool { +pub fn is_eth_address(addr: &VmAddress) -> bool { if addr.protocol() != Protocol::Delegated { return false; } diff --git a/src/wallet/subcommands/wallet_cmd.rs b/src/wallet/subcommands/wallet_cmd.rs index 1003ac31a96c..014057cc4f66 100644 --- a/src/wallet/subcommands/wallet_cmd.rs +++ b/src/wallet/subcommands/wallet_cmd.rs @@ -12,12 +12,17 @@ use crate::key_management::{Key, KeyInfo}; use crate::{ ENCRYPTED_KEYSTORE_NAME, cli::humantoken, + eth::{EAMMethod, EVMMethod, EthEip1559TxArgsBuilder, EthTx}, message::SignedMessage, rpc::{ + eth::{EthChainId, is_eth_address, types::EthAddress}, mpool::{MpoolGetNonce, MpoolPush, MpoolPushMessage}, types::ApiTipsetKey, }, - shim::address::Address, + shim::{ + address::{Address, Protocol}, + message::{METHOD_SEND, Message}, + }, }; use crate::{KeyStore, lotus_json::LotusJson}; use crate::{ @@ -26,7 +31,6 @@ use crate::{ address::StrictAddress, crypto::{Signature, SignatureType}, econ::TokenAmount, - message::{METHOD_SEND, Message}, }, }; use crate::{ @@ -499,11 +503,47 @@ impl WalletCommands { .into() }; + let (mut to, is_0x_recipient) = match StrictAddress::from_str(&target_address) { + Ok(addr) => (addr.into(), false), + Err(_) => { + let eth_addr = EthAddress::from_str(&target_address).context( + "target address must be a valid FIL address or ETH address (0x...)", + )?; + let addr = eth_addr.to_filecoin_address()?; + if addr.protocol() != Protocol::ID && addr.protocol() != Protocol::Delegated + { + bail!( + "ETH addresses can only map to FIL addresses starting with f410f/t410f or f0/t0" + ); + } + (addr, true) + } + }; + + let method_num = if is_eth_address(&from) || is_0x_recipient { + if to.protocol() != Protocol::ID && to.protocol() != Protocol::Delegated { + to = StateLookupID::call(&backend.remote, (to, ApiTipsetKey(None))) + .await + .map_err(|_| { + anyhow::anyhow!( + "addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for {to}" + ) + })?; + } + if to == Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR { + EAMMethod::CreateExternal as u64 + } else { + EVMMethod::InvokeContract as u64 + } + } else { + METHOD_SEND + }; + let message = Message { from, - to: StrictAddress::from_str(&target_address)?.into(), + to, value: amount, - method_num: METHOD_SEND, + method_num, gas_limit: gas_limit as u64, gas_fee_cap: gas_feecap, gas_premium, @@ -526,13 +566,34 @@ impl WalletCommands { message.sequence = MpoolGetNonce::call(&backend.remote, (from,)).await?; let key = crate::key_management::find_key(&from, keystore)?; - let sig = crate::key_management::sign( - *key.key_info.key_type(), - key.key_info.private_key(), - message.cid().to_bytes().as_slice(), - )?; - - let smsg = SignedMessage::new_from_parts(message, sig)?; + let sig_type = *key.key_info.key_type(); + let smsg = if sig_type == SignatureType::Delegated { + let eth_chain_id = u64::from_str_radix( + EthChainId::call(&backend.remote, ()) + .await? + .trim_start_matches("0x"), + 16, + )?; + let eth_tx_args = EthEip1559TxArgsBuilder::default() + .chain_id(eth_chain_id) + .unsigned_message(&message)? + .build()?; + let eth_tx = EthTx::Eip1559(Box::new(eth_tx_args)); + let sig = crate::key_management::sign( + sig_type, + key.key_info.private_key(), + ð_tx.rlp_unsigned_message(eth_chain_id)?, + )?; + let unsigned_msg = eth_tx.get_unsigned_message(from, eth_chain_id)?; + SignedMessage::new_unchecked(unsigned_msg, sig) + } else { + let sig = crate::key_management::sign( + sig_type, + key.key_info.private_key(), + message.cid().to_bytes().as_slice(), + )?; + SignedMessage::new_from_parts(message, sig)? + }; MpoolPush::call(&backend.remote, (smsg.clone(),)).await?; smsg From 4a662d338b3445c596a133ce992e59563505793d Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 05:13:58 +0530 Subject: [PATCH 02/17] Add wallet test --- scripts/tests/calibnet_wallet_check.sh | 84 ++++++++++++++++++++++++++ src/message_pool/msgpool/msg_pool.rs | 1 - 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index 0bd3def687ed..0fd8865ff2fc 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -115,14 +115,28 @@ sleep 5s # Show balances $FOREST_WALLET_PATH list +FOREST_URL="http://127.0.0.1:2345/rpc/v1" + echo "Creating a new address to send FIL to" ADDR_TWO=$($FOREST_WALLET_PATH new) echo "$ADDR_TWO" +ETH_ADDR_TWO=$(curl -s -X POST "$FOREST_URL" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + --data "$(jq -n --arg addr "$ADDR_TWO" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + | jq -r '.result') +echo "ETH address: $ETH_ADDR_TWO" $FOREST_WALLET_PATH set-default "$ADDR_ONE" echo "Creating a new (remote) address to send FIL to" ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new) echo "$ADDR_THREE" +ETH_ADDR_THREE=$(curl -s -X POST "$FOREST_URL" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + --data "$(jq -n --arg addr "$ADDR_THREE" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + | jq -r '.result') +echo "ETH address: $ETH_ADDR_THREE" $FOREST_WALLET_PATH --remote-wallet set-default "$ADDR_ONE" $FOREST_WALLET_PATH list @@ -131,9 +145,15 @@ $FOREST_WALLET_PATH --remote-wallet list MSG=$($FOREST_WALLET_PATH send "$ADDR_TWO" "$FIL_AMT") : "$MSG" +MSG_ETH=$($FOREST_WALLET_PATH send "$ETH_ADDR_TWO" "$FIL_AMT") +: "$MSG_ETH" + MSG_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ADDR_THREE" "$FIL_AMT") : "$MSG_REMOTE" +MSG_ETH_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ETH_ADDR_THREE" "$FIL_AMT") +: "$MSG_ETH_REMOTE" + ADDR_TWO_BALANCE=$FIL_ZERO i=0 while [[ $i != 20 && $ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do @@ -154,6 +174,70 @@ while [[ $i != 20 && $ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ADDR_THREE" --exact-balance) done +: Begin delegated wallet tests + +# The following steps test delegated (f4) wallets: create, fund from ADDR_ONE, and send to two new delegated addresses. + +echo "Creating delegated wallet DELEGATE_ADDR_ONE" +DELEGATE_ADDR_ONE=$($FOREST_WALLET_PATH new delegated) +echo "$DELEGATE_ADDR_ONE" +$FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key +$FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key + +# Fund delegated wallet from preloaded wallet +$FOREST_WALLET_PATH set-default "$ADDR_ONE" +MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$FIL_AMT") +: "$MSG_DELEGATE_FUND" + +DELEGATE_ADDR_ONE_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_ONE_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_ONE balance $i/20" + sleep 30s + DELEGATE_ADDR_ONE_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_ONE" --exact-balance) +done + +# Create new delegated addresses (local and remote) +echo "Creating delegated wallet DELEGATE_ADDR_TWO" +DELEGATE_ADDR_TWO=$($FOREST_WALLET_PATH new delegated) +echo "$DELEGATE_ADDR_TWO" +echo "Creating delegated (remote) wallet DELEGATE_ADDR_THREE" +DELEGATE_ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new delegated) +echo "$DELEGATE_ADDR_THREE" + +# Amount to send to delegated addresses +FIL_AMOUNT_DELEGATE="100 atto FIL" + +$FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" +MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMOUNT_DELEGATE") +: "$MSG_DELEGATE_TWO" +MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMOUNT_DELEGATE") +: "$MSG_DELEGATE_THREE" + +DELEGATE_ADDR_TWO_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_TWO balance $i/20" + sleep 30s + DELEGATE_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_TWO" --exact-balance) +done + +DELEGATE_ADDR_THREE_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_THREE balance $i/20" + sleep 30s + DELEGATE_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$DELEGATE_ADDR_THREE" --exact-balance) +done + +$FOREST_WALLET_PATH list +$FOREST_WALLET_PATH --remote-wallet list + +: End delegated wallet tests + # wallet list should contain address two with transferred FIL amount $FOREST_WALLET_PATH list $FOREST_WALLET_PATH --remote-wallet list diff --git a/src/message_pool/msgpool/msg_pool.rs b/src/message_pool/msgpool/msg_pool.rs index cffd326a42ab..96fecb26e758 100644 --- a/src/message_pool/msgpool/msg_pool.rs +++ b/src/message_pool/msgpool/msg_pool.rs @@ -266,7 +266,6 @@ where if to_vec(msg)?.len() > MAX_MESSAGE_SIZE { return Err(Error::MessageTooBig); } - // Reject delegated (f4) recipient if not a valid Eth address (avoids black-hole sends). let to = msg.message().to(); if to.protocol() == Protocol::Delegated && EthAddress::from_filecoin_address(&to).is_err() { return Err(Error::Other(format!( From ca1d97436e76250e2a86233f40282d0fb84cd52f Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 07:18:42 +0530 Subject: [PATCH 03/17] fix test --- scripts/tests/calibnet_wallet_check.sh | 58 ++++++++++++++++++-------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index 0fd8865ff2fc..58c614790fa8 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -120,23 +120,11 @@ FOREST_URL="http://127.0.0.1:2345/rpc/v1" echo "Creating a new address to send FIL to" ADDR_TWO=$($FOREST_WALLET_PATH new) echo "$ADDR_TWO" -ETH_ADDR_TWO=$(curl -s -X POST "$FOREST_URL" \ - -H 'Content-Type: application/json' \ - -H "Authorization: Bearer $ADMIN_TOKEN" \ - --data "$(jq -n --arg addr "$ADDR_TWO" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ - | jq -r '.result') -echo "ETH address: $ETH_ADDR_TWO" $FOREST_WALLET_PATH set-default "$ADDR_ONE" echo "Creating a new (remote) address to send FIL to" ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new) echo "$ADDR_THREE" -ETH_ADDR_THREE=$(curl -s -X POST "$FOREST_URL" \ - -H 'Content-Type: application/json' \ - -H "Authorization: Bearer $ADMIN_TOKEN" \ - --data "$(jq -n --arg addr "$ADDR_THREE" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ - | jq -r '.result') -echo "ETH address: $ETH_ADDR_THREE" $FOREST_WALLET_PATH --remote-wallet set-default "$ADDR_ONE" $FOREST_WALLET_PATH list @@ -145,15 +133,9 @@ $FOREST_WALLET_PATH --remote-wallet list MSG=$($FOREST_WALLET_PATH send "$ADDR_TWO" "$FIL_AMT") : "$MSG" -MSG_ETH=$($FOREST_WALLET_PATH send "$ETH_ADDR_TWO" "$FIL_AMT") -: "$MSG_ETH" - MSG_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ADDR_THREE" "$FIL_AMT") : "$MSG_REMOTE" -MSG_ETH_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ETH_ADDR_THREE" "$FIL_AMT") -: "$MSG_ETH_REMOTE" - ADDR_TWO_BALANCE=$FIL_ZERO i=0 while [[ $i != 20 && $ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do @@ -174,6 +156,46 @@ while [[ $i != 20 && $ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ADDR_THREE" --exact-balance) done +ETH_ADDR_TWO=$(curl -s -X POST "$FOREST_URL" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + --data "$(jq -n --arg addr "$ADDR_TWO" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + | jq -r '.result') +echo "ETH address: $ETH_ADDR_TWO" + +ETH_ADDR_THREE=$(curl -s -X POST "$FOREST_URL" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + --data "$(jq -n --arg addr "$ADDR_THREE" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + | jq -r '.result') +echo "ETH address: $ETH_ADDR_THREE" + +MSG_ETH=$($FOREST_WALLET_PATH send "$ETH_ADDR_TWO" "$FIL_AMT") +: "$MSG_ETH" + +MSG_ETH_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ETH_ADDR_THREE" "$FIL_AMT") +: "$MSG_ETH_REMOTE" + +ETH_ADDR_TWO_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $ETH_ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + + : "Checking balance $i/20" + sleep 30s + ETH_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$ETH_ADDR_TWO" --exact-balance) +done + +ETH_ADDR_THREE_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $ETH_ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + + : "Checking balance $i/20" + sleep 30s + ETH_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ETH_ADDR_THREE" --exact-balance) +done + : Begin delegated wallet tests # The following steps test delegated (f4) wallets: create, fund from ADDR_ONE, and send to two new delegated addresses. From 414f30087f2da7093e955ecfa31568783f37b7da Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 07:48:05 +0530 Subject: [PATCH 04/17] fix getting eth addr --- scripts/tests/calibnet_wallet_check.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index 58c614790fa8..f9fd7fa940a4 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -159,14 +159,14 @@ done ETH_ADDR_TWO=$(curl -s -X POST "$FOREST_URL" \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $ADMIN_TOKEN" \ - --data "$(jq -n --arg addr "$ADDR_TWO" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + --data "$(jq -n --arg addr "$ADDR_TWO" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, "pending"]}')" \ | jq -r '.result') echo "ETH address: $ETH_ADDR_TWO" ETH_ADDR_THREE=$(curl -s -X POST "$FOREST_URL" \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $ADMIN_TOKEN" \ - --data "$(jq -n --arg addr "$ADDR_THREE" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, null]}')" \ + --data "$(jq -n --arg addr "$ADDR_THREE" '{jsonrpc: "2.0", id: 1, method: "Filecoin.FilecoinAddressToEthAddress", params: [$addr, "pending"]}')" \ | jq -r '.result') echo "ETH address: $ETH_ADDR_THREE" From 1d717cde9cee24d4204a0a04e69d773e52845e79 Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 08:11:50 +0530 Subject: [PATCH 05/17] fix balance check --- scripts/tests/calibnet_wallet_check.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index f9fd7fa940a4..bfff0586d8af 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -176,24 +176,24 @@ MSG_ETH=$($FOREST_WALLET_PATH send "$ETH_ADDR_TWO" "$FIL_AMT") MSG_ETH_REMOTE=$($FOREST_WALLET_PATH --remote-wallet send "$ETH_ADDR_THREE" "$FIL_AMT") : "$MSG_ETH_REMOTE" -ETH_ADDR_TWO_BALANCE=$FIL_ZERO +ETH_ADDR_TWO_BALANCE=$ADDR_TWO_BALANCE i=0 -while [[ $i != 20 && $ETH_ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do +while [[ $i != 20 && $ETH_ADDR_TWO_BALANCE == "$ADDR_TWO_BALANCE" ]]; do i=$((i+1)) : "Checking balance $i/20" sleep 30s - ETH_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$ETH_ADDR_TWO" --exact-balance) + ETH_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$ADDR_TWO" --exact-balance) done -ETH_ADDR_THREE_BALANCE=$FIL_ZERO +ETH_ADDR_THREE_BALANCE=$ADDR_THREE_BALANCE i=0 -while [[ $i != 20 && $ETH_ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do +while [[ $i != 20 && $ETH_ADDR_THREE_BALANCE == "$ADDR_THREE_BALANCE" ]]; do i=$((i+1)) : "Checking balance $i/20" sleep 30s - ETH_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ETH_ADDR_THREE" --exact-balance) + ETH_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ADDR_THREE" --exact-balance) done : Begin delegated wallet tests From cace07c8d7ae53b8ac7b72f3e126b41c649414ab Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 09:51:28 +0530 Subject: [PATCH 06/17] fund delegate wallet for test --- scripts/tests/calibnet_wallet_check.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index bfff0586d8af..a424abc45070 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -207,8 +207,9 @@ $FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key $FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key # Fund delegated wallet from preloaded wallet +DELEGATE_FUND_AMT="1 micro FIL" $FOREST_WALLET_PATH set-default "$ADDR_ONE" -MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$FIL_AMT") +MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") : "$MSG_DELEGATE_FUND" DELEGATE_ADDR_ONE_BALANCE=$FIL_ZERO @@ -228,13 +229,10 @@ echo "Creating delegated (remote) wallet DELEGATE_ADDR_THREE" DELEGATE_ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new delegated) echo "$DELEGATE_ADDR_THREE" -# Amount to send to delegated addresses -FIL_AMOUNT_DELEGATE="100 atto FIL" - $FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" -MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMOUNT_DELEGATE") +MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMT") : "$MSG_DELEGATE_TWO" -MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMOUNT_DELEGATE") +MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMT") : "$MSG_DELEGATE_THREE" DELEGATE_ADDR_TWO_BALANCE=$FIL_ZERO From 04d7d15b7f91f6df72b92479699610d1189413a2 Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 10:29:26 +0530 Subject: [PATCH 07/17] update changelog --- CHANGELOG.md | 2 ++ scripts/tests/calibnet_wallet_check.sh | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c68a3986f4f..ddf6656d487b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ ### Added +- [#6710](https://github.com/ChainSafe/forest/pull/6710): Added support for f4 addresses in forest-wallet. + ### Changed - [#6631](https://github.com/ChainSafe/forest/issues/6631): Backported F3 finality resolution to ETH v1 RPC methods. diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index a424abc45070..e64fc392f96a 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -198,7 +198,7 @@ done : Begin delegated wallet tests -# The following steps test delegated (f4) wallets: create, fund from ADDR_ONE, and send to two new delegated addresses. +# The following steps do basic delegated wallet handling tests. echo "Creating delegated wallet DELEGATE_ADDR_ONE" DELEGATE_ADDR_ONE=$($FOREST_WALLET_PATH new delegated) @@ -221,17 +221,22 @@ while [[ $i != 20 && $DELEGATE_ADDR_ONE_BALANCE == "$FIL_ZERO" ]]; do DELEGATE_ADDR_ONE_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_ONE" --exact-balance) done -# Create new delegated addresses (local and remote) echo "Creating delegated wallet DELEGATE_ADDR_TWO" DELEGATE_ADDR_TWO=$($FOREST_WALLET_PATH new delegated) echo "$DELEGATE_ADDR_TWO" +$FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" + echo "Creating delegated (remote) wallet DELEGATE_ADDR_THREE" DELEGATE_ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new delegated) echo "$DELEGATE_ADDR_THREE" +$FOREST_WALLET_PATH --remote-wallet set-default "$DELEGATE_ADDR_ONE" + +$FOREST_WALLET_PATH list +$FOREST_WALLET_PATH --remote-wallet list -$FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMT") : "$MSG_DELEGATE_TWO" + MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMT") : "$MSG_DELEGATE_THREE" From 6b652f2d14ec257e4f87d60f4b243ceb4075a13a Mon Sep 17 00:00:00 2001 From: Shashank Date: Tue, 10 Mar 2026 11:02:57 +0530 Subject: [PATCH 08/17] increase delegate test wallet fund --- scripts/tests/calibnet_wallet_check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index e64fc392f96a..907ff7437e45 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -207,7 +207,7 @@ $FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key $FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key # Fund delegated wallet from preloaded wallet -DELEGATE_FUND_AMT="1 micro FIL" +DELEGATE_FUND_AMT="2 micro FIL" $FOREST_WALLET_PATH set-default "$ADDR_ONE" MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") : "$MSG_DELEGATE_FUND" From ed652e8c805bc63ab7129981eab4aa702f91283e Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 15:02:02 +0530 Subject: [PATCH 09/17] refactor and add test --- src/wallet/subcommands/wallet_cmd.rs | 203 ++++++++++++++++++++++----- 1 file changed, 168 insertions(+), 35 deletions(-) diff --git a/src/wallet/subcommands/wallet_cmd.rs b/src/wallet/subcommands/wallet_cmd.rs index 014057cc4f66..0177d7cd0daa 100644 --- a/src/wallet/subcommands/wallet_cmd.rs +++ b/src/wallet/subcommands/wallet_cmd.rs @@ -503,41 +503,22 @@ impl WalletCommands { .into() }; - let (mut to, is_0x_recipient) = match StrictAddress::from_str(&target_address) { - Ok(addr) => (addr.into(), false), - Err(_) => { - let eth_addr = EthAddress::from_str(&target_address).context( - "target address must be a valid FIL address or ETH address (0x...)", - )?; - let addr = eth_addr.to_filecoin_address()?; - if addr.protocol() != Protocol::ID && addr.protocol() != Protocol::Delegated - { - bail!( - "ETH addresses can only map to FIL addresses starting with f410f/t410f or f0/t0" - ); - } - (addr, true) - } - }; - - let method_num = if is_eth_address(&from) || is_0x_recipient { - if to.protocol() != Protocol::ID && to.protocol() != Protocol::Delegated { - to = StateLookupID::call(&backend.remote, (to, ApiTipsetKey(None))) - .await - .map_err(|_| { - anyhow::anyhow!( - "addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for {to}" - ) - })?; - } - if to == Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR { - EAMMethod::CreateExternal as u64 - } else { - EVMMethod::InvokeContract as u64 - } - } else { - METHOD_SEND - }; + let (mut to, is_0x_recipient) = resolve_target_address(&target_address)?; + + // Resolve to ID address when sending from delegated address to non-ID/non-Delegated address. + if is_eth_address(&from) + && to.protocol() != Protocol::ID + && to.protocol() != Protocol::Delegated + { + to = StateLookupID::call(&backend.remote, (to.clone(), ApiTipsetKey(None))) + .await + .map_err(|_| { + anyhow::anyhow!( + "addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for {to}" + ) + })?; + } + let method_num = resolve_method_num(&from, &to, is_0x_recipient)?; let message = Message { from, @@ -656,3 +637,155 @@ fn format_balance(balance: &TokenAmount, no_round: bool, no_abbrev: bool) -> Str (false, false) => format!("{:.4}", balance.pretty()), } } + +fn resolve_target_address(target_address: &str) -> anyhow::Result<(Address, bool)> { + match StrictAddress::from_str(target_address) { + Ok(addr) => Ok((addr.into(), false)), + Err(_) => { + let eth_addr = EthAddress::from_str(target_address) + .context("target address must be a valid FIL address or ETH address (0x...)")?; + let addr = eth_addr.to_filecoin_address()?; + Ok((addr, true)) + } + } +} + +fn resolve_method_num(from: &Address, to: &Address, is_0x_recipient: bool) -> anyhow::Result { + if !is_eth_address(from) && !is_0x_recipient { + return Ok(METHOD_SEND); + } + if *to == Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR { + Ok(EAMMethod::CreateExternal as u64) + } else { + Ok(EVMMethod::InvokeContract as u64) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::eth::{EAMMethod, EVMMethod}; + use crate::rpc::eth::types::EthAddress; + use crate::shim::address::{Address, CurrentNetwork, Network}; + use crate::shim::message::METHOD_SEND; + + use super::{resolve_method_num, resolve_target_address}; + + #[test] + fn test_resolve_target_address_id() { + CurrentNetwork::with(Network::Mainnet, || { + let (addr, is_0x) = resolve_target_address("f01234").unwrap(); + assert!(!is_0x); + let expected_addr = Address::new_id(1234); + assert_eq!(addr, expected_addr); + }); + CurrentNetwork::with(Network::Testnet, || { + let (addr, is_0x) = resolve_target_address("t01234").unwrap(); + assert!(!is_0x); + let expected_addr = Address::new_id(1234); + assert_eq!(addr, expected_addr); + }); + } + + #[test] + fn test_resolve_target_address_masked_id() { + CurrentNetwork::with(Network::Mainnet, || { + let (addr, is_0x) = + resolve_target_address("0xff000000000000000000000000000000000004d2").unwrap(); + assert!(is_0x); + let expected_addr = Address::new_id(1234); + assert_eq!(addr, expected_addr); + }); + CurrentNetwork::with(Network::Testnet, || { + let (addr, is_0x) = + resolve_target_address("0xff000000000000000000000000000000000004d2").unwrap(); + assert!(is_0x); + let expected_addr = Address::new_id(1234); + assert_eq!(addr, expected_addr); + }); + } + + #[test] + fn test_resolve_target_address_eth() { + CurrentNetwork::with(Network::Mainnet, || { + let (addr, is_0x) = + resolve_target_address("0x6cb414224f0b91de5c3b616e700e34a5172c149f").unwrap(); + assert!(is_0x); + let expected_addr = + Address::from_str("f410fns2biispboi54xb3mfxhadruuulsyfe73avfmey").unwrap(); + assert_eq!(addr, expected_addr); + }); + CurrentNetwork::with(Network::Testnet, || { + let (addr, is_0x) = + resolve_target_address("0x6cb414224f0b91de5c3b616e700e34a5172c149f").unwrap(); + assert!(is_0x); + let expected_addr = + Address::from_str("t410fns2biispboi54xb3mfxhadruuulsyfe73avfmey").unwrap(); + assert_eq!(addr, expected_addr); + }); + } + + #[test] + fn test_resolve_target_address_invalid() { + let err = resolve_target_address("0xInvalidAddress").unwrap_err(); + assert!( + err.to_string() + .contains("target address must be a valid FIL address or ETH address") + ); + } + + #[test] + fn test_resolve_method_num_send() { + let from = Address::from_str("f01234").unwrap(); + let to = Address::from_str("f01234").unwrap(); + let method = resolve_method_num(&from, &to, false).unwrap(); + assert_eq!(method, METHOD_SEND); + } + + #[test] + fn test_resolve_method_num_create_external() { + let from = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); + let to = Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR; + let method = resolve_method_num(&from, &to, false).unwrap(); + assert_eq!(method, EAMMethod::CreateExternal as u64); + } + + #[test] + fn test_resolve_method_num_invoke_contract() { + let from = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); + let to = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); + let method = resolve_method_num(&from, &to, false).unwrap(); + assert_eq!(method, EVMMethod::InvokeContract as u64); + } + + #[test] + fn test_resolve_method_num_invoke_contract_eth() { + let from = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); + let to = EthAddress::from_str("0x6cb414224f0b91de5c3b616e700e34a5172c149f") + .unwrap() + .to_filecoin_address() + .unwrap(); + let method = resolve_method_num(&from, &to, true).unwrap(); + assert_eq!(method, EVMMethod::InvokeContract as u64); + } + + #[test] + fn test_resolve_method_num_send_to_delegated() { + let from = Address::from_str("f01234").unwrap(); + let to = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); + let method = resolve_method_num(&from, &to, false).unwrap(); + assert_eq!(method, METHOD_SEND); + } + + #[test] + fn test_resolve_method_num_send_to_eth() { + let from = Address::from_str("f01234").unwrap(); + let to = EthAddress::from_str("0x6cb414224f0b91de5c3b616e700e34a5172c149f") + .unwrap() + .to_filecoin_address() + .unwrap(); + let method = resolve_method_num(&from, &to, true).unwrap(); + assert_eq!(method, EVMMethod::InvokeContract as u64); + } +} From 3c928c8a79adf4dea30d3cbfb093dc80f99d9418 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 15:16:44 +0530 Subject: [PATCH 10/17] refactor resolve_method_num --- src/wallet/subcommands/wallet_cmd.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/wallet/subcommands/wallet_cmd.rs b/src/wallet/subcommands/wallet_cmd.rs index 0177d7cd0daa..7327f39e27e1 100644 --- a/src/wallet/subcommands/wallet_cmd.rs +++ b/src/wallet/subcommands/wallet_cmd.rs @@ -518,7 +518,7 @@ impl WalletCommands { ) })?; } - let method_num = resolve_method_num(&from, &to, is_0x_recipient)?; + let method_num = resolve_method_num(&from, &to, is_0x_recipient); let message = Message { from, @@ -650,14 +650,14 @@ fn resolve_target_address(target_address: &str) -> anyhow::Result<(Address, bool } } -fn resolve_method_num(from: &Address, to: &Address, is_0x_recipient: bool) -> anyhow::Result { +fn resolve_method_num(from: &Address, to: &Address, is_0x_recipient: bool) -> u64 { if !is_eth_address(from) && !is_0x_recipient { - return Ok(METHOD_SEND); + return METHOD_SEND; } if *to == Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR { - Ok(EAMMethod::CreateExternal as u64) + EAMMethod::CreateExternal as u64 } else { - Ok(EVMMethod::InvokeContract as u64) + EVMMethod::InvokeContract as u64 } } @@ -739,7 +739,7 @@ mod tests { fn test_resolve_method_num_send() { let from = Address::from_str("f01234").unwrap(); let to = Address::from_str("f01234").unwrap(); - let method = resolve_method_num(&from, &to, false).unwrap(); + let method = resolve_method_num(&from, &to, false); assert_eq!(method, METHOD_SEND); } @@ -747,7 +747,7 @@ mod tests { fn test_resolve_method_num_create_external() { let from = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); let to = Address::ETHEREUM_ACCOUNT_MANAGER_ACTOR; - let method = resolve_method_num(&from, &to, false).unwrap(); + let method = resolve_method_num(&from, &to, false); assert_eq!(method, EAMMethod::CreateExternal as u64); } @@ -755,7 +755,7 @@ mod tests { fn test_resolve_method_num_invoke_contract() { let from = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); let to = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); - let method = resolve_method_num(&from, &to, false).unwrap(); + let method = resolve_method_num(&from, &to, false); assert_eq!(method, EVMMethod::InvokeContract as u64); } @@ -766,7 +766,7 @@ mod tests { .unwrap() .to_filecoin_address() .unwrap(); - let method = resolve_method_num(&from, &to, true).unwrap(); + let method = resolve_method_num(&from, &to, true); assert_eq!(method, EVMMethod::InvokeContract as u64); } @@ -774,7 +774,7 @@ mod tests { fn test_resolve_method_num_send_to_delegated() { let from = Address::from_str("f01234").unwrap(); let to = Address::from_str("f410fvfpyxvy6aqet3g2bfbj6h7nr5kjgyncpaeimgxa").unwrap(); - let method = resolve_method_num(&from, &to, false).unwrap(); + let method = resolve_method_num(&from, &to, false); assert_eq!(method, METHOD_SEND); } @@ -785,7 +785,7 @@ mod tests { .unwrap() .to_filecoin_address() .unwrap(); - let method = resolve_method_num(&from, &to, true).unwrap(); + let method = resolve_method_num(&from, &to, true); assert_eq!(method, EVMMethod::InvokeContract as u64); } } From 675da0a331e34ee40d629f5708750b887e6e6be7 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 15:46:52 +0530 Subject: [PATCH 11/17] lint fix --- src/wallet/subcommands/wallet_cmd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/subcommands/wallet_cmd.rs b/src/wallet/subcommands/wallet_cmd.rs index 7327f39e27e1..aed63871327c 100644 --- a/src/wallet/subcommands/wallet_cmd.rs +++ b/src/wallet/subcommands/wallet_cmd.rs @@ -512,8 +512,8 @@ impl WalletCommands { { to = StateLookupID::call(&backend.remote, (to.clone(), ApiTipsetKey(None))) .await - .map_err(|_| { - anyhow::anyhow!( + .with_context(|| { + format!( "addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for {to}" ) })?; From 4b7ac40d65a7e7bec1304f1f06d85b72dd1872e2 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 16:25:21 +0530 Subject: [PATCH 12/17] more lint fix --- src/wallet/subcommands/wallet_cmd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/subcommands/wallet_cmd.rs b/src/wallet/subcommands/wallet_cmd.rs index aed63871327c..62cb3f6c8fa2 100644 --- a/src/wallet/subcommands/wallet_cmd.rs +++ b/src/wallet/subcommands/wallet_cmd.rs @@ -510,7 +510,7 @@ impl WalletCommands { && to.protocol() != Protocol::ID && to.protocol() != Protocol::Delegated { - to = StateLookupID::call(&backend.remote, (to.clone(), ApiTipsetKey(None))) + to = StateLookupID::call(&backend.remote, (to, ApiTipsetKey(None))) .await .with_context(|| { format!( From a8a54a5d3a5e9c8492609c0b87b464f9dfda0a8f Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 19:27:31 +0530 Subject: [PATCH 13/17] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10052d69cccb..fae3bbb8d1f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ ### Added +- [#6710](https://github.com/ChainSafe/forest/pull/6710): Added support for f4 addresses in forest-wallet. + ### Changed ### Removed @@ -45,8 +47,6 @@ This is a non-mandatory release for all node operators. It enables F3 finality r ### Added -- [#6710](https://github.com/ChainSafe/forest/pull/6710): Added support for f4 addresses in forest-wallet. - ### Changed - [#6631](https://github.com/ChainSafe/forest/issues/6631): Backported F3 finality resolution to ETH v1 RPC methods. From 4fa870ac8e83e21029fb71347ca0fb8516db8ce0 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 20:36:51 +0530 Subject: [PATCH 14/17] refactor test --- .github/workflows/forest.yml | 1 + .../tests/calibnet_delegated_wallet_check.sh | 87 +++++++++++++++++++ scripts/tests/calibnet_wallet_check.sh | 68 --------------- src/message_pool/msgpool/msg_pool.rs | 6 +- 4 files changed, 91 insertions(+), 71 deletions(-) create mode 100755 scripts/tests/calibnet_delegated_wallet_check.sh diff --git a/.github/workflows/forest.yml b/.github/workflows/forest.yml index 79d1b61030d2..7d2f7d14d253 100644 --- a/.github/workflows/forest.yml +++ b/.github/workflows/forest.yml @@ -268,6 +268,7 @@ jobs: run: | if [[ "$CALIBNET_WALLET" != "" ]]; then ./scripts/tests/calibnet_wallet_check.sh "$CALIBNET_WALLET" + ./scripts/tests/calibnet_delegated_wallet_check.sh "$CALIBNET_WALLET" fi timeout-minutes: ${{ fromJSON(env.SCRIPT_TIMEOUT_MINUTES) }} calibnet-export-check-v1: diff --git a/scripts/tests/calibnet_delegated_wallet_check.sh b/scripts/tests/calibnet_delegated_wallet_check.sh new file mode 100755 index 000000000000..6b1472cbf333 --- /dev/null +++ b/scripts/tests/calibnet_delegated_wallet_check.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# This script checks delegated wallet features of the forest node and the forest-cli. +# It requires both `forest` and `forest-cli` to be in the PATH. + +set -euxo pipefail + +source "$(dirname "$0")/harness.sh" + +forest_init "$@" + +# Amount to send (note: `send` command defaults to FIL if no units are specified) +FIL_AMT="500 atto FIL" + +# Amount for an empty wallet +FIL_ZERO="0 FIL" + +# The preloaded address +ADDR_ONE=$($FOREST_WALLET_PATH list | tail -1 | cut -d ' ' -f1) + +sleep 5s + +: Begin delegated wallet tests + +# The following steps do basic delegated wallet handling tests. + +echo "Creating delegated wallet DELEGATE_ADDR_ONE" +DELEGATE_ADDR_ONE=$($FOREST_WALLET_PATH new delegated) +echo "$DELEGATE_ADDR_ONE" +$FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key +$FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key + +# Fund delegated wallet from preloaded wallet +DELEGATE_FUND_AMT="2 micro FIL" +$FOREST_WALLET_PATH set-default "$ADDR_ONE" +MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") +: "$MSG_DELEGATE_FUND" + +DELEGATE_ADDR_ONE_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_ONE_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_ONE balance $i/20" + sleep 30s + DELEGATE_ADDR_ONE_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_ONE" --exact-balance) +done + +echo "Creating delegated wallet DELEGATE_ADDR_TWO" +DELEGATE_ADDR_TWO=$($FOREST_WALLET_PATH new delegated) +echo "$DELEGATE_ADDR_TWO" +$FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" + +echo "Creating delegated (remote) wallet DELEGATE_ADDR_THREE" +DELEGATE_ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new delegated) +echo "$DELEGATE_ADDR_THREE" +$FOREST_WALLET_PATH --remote-wallet set-default "$DELEGATE_ADDR_ONE" + +$FOREST_WALLET_PATH list +$FOREST_WALLET_PATH --remote-wallet list + +MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMT") +: "$MSG_DELEGATE_TWO" + +MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMT") +: "$MSG_DELEGATE_THREE" + +DELEGATE_ADDR_TWO_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_TWO balance $i/20" + sleep 30s + DELEGATE_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_TWO" --exact-balance) +done + +DELEGATE_ADDR_THREE_BALANCE=$FIL_ZERO +i=0 +while [[ $i != 20 && $DELEGATE_ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do + i=$((i+1)) + : "Checking DELEGATE_ADDR_THREE balance $i/20" + sleep 30s + DELEGATE_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$DELEGATE_ADDR_THREE" --exact-balance) +done + +$FOREST_WALLET_PATH list +$FOREST_WALLET_PATH --remote-wallet list + +: End delegated wallet tests diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index 907ff7437e45..08412476da8e 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -7,7 +7,6 @@ set -euxo pipefail source "$(dirname "$0")/harness.sh" - usage() { echo "Usage: $0 " exit 1 @@ -196,73 +195,6 @@ while [[ $i != 20 && $ETH_ADDR_THREE_BALANCE == "$ADDR_THREE_BALANCE" ]]; do ETH_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$ADDR_THREE" --exact-balance) done -: Begin delegated wallet tests - -# The following steps do basic delegated wallet handling tests. - -echo "Creating delegated wallet DELEGATE_ADDR_ONE" -DELEGATE_ADDR_ONE=$($FOREST_WALLET_PATH new delegated) -echo "$DELEGATE_ADDR_ONE" -$FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key -$FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key - -# Fund delegated wallet from preloaded wallet -DELEGATE_FUND_AMT="2 micro FIL" -$FOREST_WALLET_PATH set-default "$ADDR_ONE" -MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") -: "$MSG_DELEGATE_FUND" - -DELEGATE_ADDR_ONE_BALANCE=$FIL_ZERO -i=0 -while [[ $i != 20 && $DELEGATE_ADDR_ONE_BALANCE == "$FIL_ZERO" ]]; do - i=$((i+1)) - : "Checking DELEGATE_ADDR_ONE balance $i/20" - sleep 30s - DELEGATE_ADDR_ONE_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_ONE" --exact-balance) -done - -echo "Creating delegated wallet DELEGATE_ADDR_TWO" -DELEGATE_ADDR_TWO=$($FOREST_WALLET_PATH new delegated) -echo "$DELEGATE_ADDR_TWO" -$FOREST_WALLET_PATH set-default "$DELEGATE_ADDR_ONE" - -echo "Creating delegated (remote) wallet DELEGATE_ADDR_THREE" -DELEGATE_ADDR_THREE=$($FOREST_WALLET_PATH --remote-wallet new delegated) -echo "$DELEGATE_ADDR_THREE" -$FOREST_WALLET_PATH --remote-wallet set-default "$DELEGATE_ADDR_ONE" - -$FOREST_WALLET_PATH list -$FOREST_WALLET_PATH --remote-wallet list - -MSG_DELEGATE_TWO=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_TWO" "$FIL_AMT") -: "$MSG_DELEGATE_TWO" - -MSG_DELEGATE_THREE=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_THREE" "$FIL_AMT") -: "$MSG_DELEGATE_THREE" - -DELEGATE_ADDR_TWO_BALANCE=$FIL_ZERO -i=0 -while [[ $i != 20 && $DELEGATE_ADDR_TWO_BALANCE == "$FIL_ZERO" ]]; do - i=$((i+1)) - : "Checking DELEGATE_ADDR_TWO balance $i/20" - sleep 30s - DELEGATE_ADDR_TWO_BALANCE=$($FOREST_WALLET_PATH balance "$DELEGATE_ADDR_TWO" --exact-balance) -done - -DELEGATE_ADDR_THREE_BALANCE=$FIL_ZERO -i=0 -while [[ $i != 20 && $DELEGATE_ADDR_THREE_BALANCE == "$FIL_ZERO" ]]; do - i=$((i+1)) - : "Checking DELEGATE_ADDR_THREE balance $i/20" - sleep 30s - DELEGATE_ADDR_THREE_BALANCE=$($FOREST_WALLET_PATH --remote-wallet balance "$DELEGATE_ADDR_THREE" --exact-balance) -done - -$FOREST_WALLET_PATH list -$FOREST_WALLET_PATH --remote-wallet list - -: End delegated wallet tests - # wallet list should contain address two with transferred FIL amount $FOREST_WALLET_PATH list $FOREST_WALLET_PATH --remote-wallet list diff --git a/src/message_pool/msgpool/msg_pool.rs b/src/message_pool/msgpool/msg_pool.rs index 96fecb26e758..6333df24debd 100644 --- a/src/message_pool/msgpool/msg_pool.rs +++ b/src/message_pool/msgpool/msg_pool.rs @@ -267,10 +267,10 @@ where return Err(Error::MessageTooBig); } let to = msg.message().to(); - if to.protocol() == Protocol::Delegated && EthAddress::from_filecoin_address(&to).is_err() { - return Err(Error::Other(format!( + if to.protocol() == Protocol::Delegated { + EthAddress::from_filecoin_address(&to).context(format!( "message recipient {to} is a delegated address but not a valid Eth Address" - ))); + ))?; } valid_for_block_inclusion(msg.message(), Gas::new(0), NEWEST_NETWORK_VERSION)?; if msg.value() > *crate::shim::econ::TOTAL_FILECOIN { From 51275e3a0736cc7b098962b5705ff004dc74e876 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 22:02:01 +0530 Subject: [PATCH 15/17] run wallet tests in parallel --- .github/workflows/forest.yml | 26 +++++++++++++++++++ .../tests/calibnet_delegated_wallet_check.sh | 2 +- scripts/tests/calibnet_wallet_check.sh | 17 +----------- scripts/tests/harness.sh | 19 ++++++++++++++ 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/.github/workflows/forest.yml b/.github/workflows/forest.yml index 7d2f7d14d253..2b9a7edc9035 100644 --- a/.github/workflows/forest.yml +++ b/.github/workflows/forest.yml @@ -268,6 +268,32 @@ jobs: run: | if [[ "$CALIBNET_WALLET" != "" ]]; then ./scripts/tests/calibnet_wallet_check.sh "$CALIBNET_WALLET" + fi + timeout-minutes: ${{ fromJSON(env.SCRIPT_TIMEOUT_MINUTES) }} + calibnet-delegated-wallet-check: + needs: + - build-ubuntu + name: Delegated wallet tests + runs-on: ubuntu-24.04 + steps: + - run: lscpu + - uses: actions/cache@v5 + with: + path: "${{ env.FIL_PROOFS_PARAMETER_CACHE }}" + key: proof-params-keys + - uses: actions/checkout@v6 + - uses: actions/download-artifact@v8 + with: + name: "forest-${{ runner.os }}" + path: ~/.cargo/bin + - name: Set permissions + run: | + chmod +x ~/.cargo/bin/forest* + - name: Delegated wallet commands check + env: + CALIBNET_WALLET: "${{ secrets.CALIBNET_WALLET }}" + run: | + if [[ "$CALIBNET_WALLET" != "" ]]; then ./scripts/tests/calibnet_delegated_wallet_check.sh "$CALIBNET_WALLET" fi timeout-minutes: ${{ fromJSON(env.SCRIPT_TIMEOUT_MINUTES) }} diff --git a/scripts/tests/calibnet_delegated_wallet_check.sh b/scripts/tests/calibnet_delegated_wallet_check.sh index 6b1472cbf333..90790f0e8697 100755 --- a/scripts/tests/calibnet_delegated_wallet_check.sh +++ b/scripts/tests/calibnet_delegated_wallet_check.sh @@ -6,7 +6,7 @@ set -euxo pipefail source "$(dirname "$0")/harness.sh" -forest_init "$@" +forest_wallet_init "$@" # Amount to send (note: `send` command defaults to FIL if no units are specified) FIL_AMT="500 atto FIL" diff --git a/scripts/tests/calibnet_wallet_check.sh b/scripts/tests/calibnet_wallet_check.sh index 08412476da8e..550c5604e3c4 100755 --- a/scripts/tests/calibnet_wallet_check.sh +++ b/scripts/tests/calibnet_wallet_check.sh @@ -7,22 +7,7 @@ set -euxo pipefail source "$(dirname "$0")/harness.sh" -usage() { - echo "Usage: $0 " - exit 1 -} - -if [ -z "$1" ] - then - usage -fi - -echo "$1" > preloaded_wallet.key - -forest_init "$@" - -$FOREST_WALLET_PATH import preloaded_wallet.key -$FOREST_WALLET_PATH --remote-wallet import preloaded_wallet.key +forest_wallet_init "$@" # Test commented out due to it being flaky. See the tracking issue: https://github.com/ChainSafe/forest/issues/4849 # : Begin Filecoin.MarketAddBalance test diff --git a/scripts/tests/harness.sh b/scripts/tests/harness.sh index f949b7700ab6..0ab83f6399c4 100644 --- a/scripts/tests/harness.sh +++ b/scripts/tests/harness.sh @@ -141,6 +141,25 @@ function forest_init_stateless { export FULLNODE_API_INFO } +function forest_wallet_init { + usage() { + echo "Usage: $0 " + exit 1 + } + + if [ -z "$1" ] + then + usage + fi + + echo "$1" > preloaded_wallet.key + + forest_init "$@" + + $FOREST_WALLET_PATH import preloaded_wallet.key + $FOREST_WALLET_PATH --remote-wallet import preloaded_wallet.key +} + function forest_print_logs_and_metrics { echo "Get and print metrics" wget -O metrics.log http://localhost:6116/metrics From 90aa7b10011c66e6af535915f2fda630ae26a5a8 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 11 Mar 2026 22:57:45 +0530 Subject: [PATCH 16/17] Increase delegated wallet test fund --- scripts/tests/calibnet_delegated_wallet_check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/calibnet_delegated_wallet_check.sh b/scripts/tests/calibnet_delegated_wallet_check.sh index 90790f0e8697..b890d1726ff2 100755 --- a/scripts/tests/calibnet_delegated_wallet_check.sh +++ b/scripts/tests/calibnet_delegated_wallet_check.sh @@ -30,7 +30,7 @@ $FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key $FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key # Fund delegated wallet from preloaded wallet -DELEGATE_FUND_AMT="2 micro FIL" +DELEGATE_FUND_AMT="3 micro FIL" $FOREST_WALLET_PATH set-default "$ADDR_ONE" MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") : "$MSG_DELEGATE_FUND" From 65dd5179f4f0755d6f8cc584c7e6f68ccd8db350 Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 12 Mar 2026 07:03:53 +0530 Subject: [PATCH 17/17] send only required fund --- scripts/tests/calibnet_delegated_wallet_check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/calibnet_delegated_wallet_check.sh b/scripts/tests/calibnet_delegated_wallet_check.sh index b890d1726ff2..90790f0e8697 100755 --- a/scripts/tests/calibnet_delegated_wallet_check.sh +++ b/scripts/tests/calibnet_delegated_wallet_check.sh @@ -30,7 +30,7 @@ $FOREST_WALLET_PATH export "$DELEGATE_ADDR_ONE" > delegated_wallet.key $FOREST_WALLET_PATH --remote-wallet import delegated_wallet.key # Fund delegated wallet from preloaded wallet -DELEGATE_FUND_AMT="3 micro FIL" +DELEGATE_FUND_AMT="2 micro FIL" $FOREST_WALLET_PATH set-default "$ADDR_ONE" MSG_DELEGATE_FUND=$($FOREST_WALLET_PATH send "$DELEGATE_ADDR_ONE" "$DELEGATE_FUND_AMT") : "$MSG_DELEGATE_FUND"