11use std:: str:: FromStr ;
22
3- use crate :: Cast ;
3+ use crate :: { format_uint_exp , tx :: signing_provider } ;
44use alloy_eips:: BlockId ;
55use alloy_ens:: NameOrAddress ;
66use alloy_primitives:: U256 ;
7+ use alloy_sol_types:: sol;
78use clap:: Parser ;
89use foundry_cli:: {
910 opts:: RpcOpts ,
1011 utils:: { LoadConfig , get_provider} ,
1112} ;
12- use foundry_common:: fmt:: format_uint_exp;
1313use foundry_wallets:: WalletOpts ;
1414
1515#[ doc( hidden) ]
1616pub use foundry_config:: utils:: * ;
1717
18+ sol ! {
19+ #[ sol( rpc) ]
20+ interface IERC20 {
21+ #[ derive( Debug ) ]
22+ function balanceOf( address owner) external view returns ( uint256) ;
23+ function transfer( address to, uint256 amount) external returns ( bool ) ;
24+ function approve( address spender, uint256 amount) external returns ( bool ) ;
25+ function allowance( address owner, address spender) external view returns ( uint256) ;
26+ }
27+ }
28+
1829/// Interact with ERC20 tokens.
1930#[ derive( Debug , Parser , Clone ) ]
2031pub enum Erc20Subcommand {
@@ -51,10 +62,6 @@ pub enum Erc20Subcommand {
5162 /// The amount to transfer.
5263 amount : String ,
5364
54- /// The block height to query at.
55- #[ arg( long, short = 'B' ) ]
56- block : Option < BlockId > ,
57-
5865 #[ command( flatten) ]
5966 rpc : RpcOpts ,
6067
@@ -76,10 +83,6 @@ pub enum Erc20Subcommand {
7683 /// The amount to approve.
7784 amount : String ,
7885
79- /// The block height to query at.
80- #[ arg( long, short = 'B' ) ]
81- block : Option < BlockId > ,
82-
8386 #[ command( flatten) ]
8487 rpc : RpcOpts ,
8588
@@ -112,60 +115,65 @@ pub enum Erc20Subcommand {
112115}
113116
114117impl Erc20Subcommand {
118+ fn rpc ( & self ) -> & RpcOpts {
119+ match self {
120+ Self :: Allowance { rpc, .. } => rpc,
121+ Self :: Approve { rpc, .. } => rpc,
122+ Self :: Balance { rpc, .. } => rpc,
123+ Self :: Transfer { rpc, .. } => rpc,
124+ }
125+ }
126+
115127 pub async fn run ( self ) -> eyre:: Result < ( ) > {
128+ let config = self . rpc ( ) . load_config ( ) ?;
129+ let provider = get_provider ( & config) ?;
130+
116131 match self {
117- Self :: Balance { token, owner, block, rpc } => {
118- let config = rpc. load_config ( ) ?;
119- let provider = get_provider ( & config) ?;
120- let owner_addr = owner. resolve ( & provider) . await ?;
121- let token_addr = token. resolve ( & provider) . await ?;
122- let balance =
123- Cast :: new ( & provider) . erc20_balance ( token_addr, owner_addr, block) . await ?;
124- sh_println ! ( "{}" , format_uint_exp( balance) ) ?
125- }
126- Self :: Transfer { token, to, amount, block : _, rpc, wallet } => {
127- let config = rpc. load_config ( ) ?;
128- let provider = get_provider ( & config) ?;
129- let to_addr = to. resolve ( & provider) . await ?;
130- let token_addr = token. resolve ( & provider) . await ?;
131- let amount_u256 = U256 :: from_str ( & amount) ?;
132-
133- // Create signer from wallet options if available
134- let signer = wallet. signer ( ) . await . ok ( ) ;
135-
136- let tx_hash = Cast :: new ( & provider)
137- . erc20_transfer ( token_addr, to_addr, amount_u256, signer)
132+ // Read-only
133+ Self :: Allowance { token, owner, spender, block, .. } => {
134+ let token = token. resolve ( & provider) . await ?;
135+ let owner = owner. resolve ( & provider) . await ?;
136+ let spender = spender. resolve ( & provider) . await ?;
137+
138+ let allowance = IERC20 :: new ( token, & provider)
139+ . allowance ( owner, spender)
140+ . block ( block. unwrap_or_default ( ) )
141+ . call ( )
138142 . await ?;
139- sh_println ! ( "{}" , tx_hash) ?
143+
144+ sh_println ! ( "{}" , format_uint_exp( allowance) ) ?
140145 }
141- Self :: Approve { token, spender, amount, block : _, rpc, wallet } => {
142- let config = rpc. load_config ( ) ?;
143- let provider = get_provider ( & config) ?;
144- let spender_addr = spender. resolve ( & provider) . await ?;
145- let token_addr = token. resolve ( & provider) . await ?;
146- let amount_u256 = U256 :: from_str ( & amount) ?;
147-
148- // Create signer from wallet options if available
149- let signer = wallet. signer ( ) . await . ok ( ) ;
150-
151- let tx_hash = Cast :: new ( & provider)
152- . erc20_approve ( token_addr, spender_addr, amount_u256, signer)
146+ Self :: Balance { token, owner, block, .. } => {
147+ let token = token. resolve ( & provider) . await ?;
148+ let owner = owner. resolve ( & provider) . await ?;
149+
150+ let balance = IERC20 :: new ( token, & provider)
151+ . balanceOf ( owner)
152+ . block ( block. unwrap_or_default ( ) )
153+ . call ( )
153154 . await ?;
154- sh_println ! ( "{}" , tx_hash ) ?
155+ sh_println ! ( "{}" , format_uint_exp ( balance ) ) ?
155156 }
156- Self :: Allowance { token, owner, spender, block, rpc } => {
157- let config = rpc. load_config ( ) ?;
158- let provider = get_provider ( & config) ?;
159- let owner_addr = owner. resolve ( & provider) . await ?;
160- let spender_addr = spender. resolve ( & provider) . await ?;
161- let token_addr = token. resolve ( & provider) . await ?;
162-
163- let allowance = Cast :: new ( & provider)
164- . erc20_allowance ( token_addr, owner_addr, spender_addr, block)
165- . await ?;
166- sh_println ! ( "{}" , format_uint_exp( allowance) ) ?
157+ // State-changing
158+ Self :: Transfer { token, to, amount, wallet, .. } => {
159+ let token = token. resolve ( & provider) . await ?;
160+ let to = to. resolve ( & provider) . await ?;
161+ let amount = U256 :: from_str ( & amount) ?;
162+
163+ let provider = signing_provider ( wallet, & provider) . await ?;
164+ let tx = IERC20 :: new ( token, & provider) . transfer ( to, amount) . send ( ) . await ?;
165+ sh_println ! ( "{}" , tx. tx_hash( ) ) ?
167166 }
168- }
167+ Self :: Approve { token, spender, amount, wallet, .. } => {
168+ let token = token. resolve ( & provider) . await ?;
169+ let spender = spender. resolve ( & provider) . await ?;
170+ let amount = U256 :: from_str ( & amount) ?;
171+
172+ let provider = signing_provider ( wallet, & provider) . await ?;
173+ let tx = IERC20 :: new ( token, & provider) . approve ( spender, amount) . send ( ) . await ?;
174+ sh_println ! ( "{}" , tx. tx_hash( ) ) ?
175+ }
176+ } ;
169177 Ok ( ( ) )
170178 }
171179}
0 commit comments