22use std:: convert:: TryFrom ;
33use std:: env;
44use std:: ffi:: OsString ;
5+ use std:: fmt:: Debug ;
56use std:: path:: PathBuf ;
67use std:: str:: FromStr ;
78
@@ -10,7 +11,6 @@ use coins_bip32::path::DerivationPath;
1011use anyhow:: anyhow;
1112use anyhow:: Context as _;
1213use ethers:: abi:: Detokenize ;
13- use ethers:: prelude:: builders:: ContractCall ;
1414use ethers:: prelude:: * ;
1515use ethers:: types:: transaction:: eip712:: Eip712 ;
1616use ethers:: types:: Chain ;
@@ -22,7 +22,7 @@ pub mod signer;
2222
2323mod walletconnect;
2424
25- use self :: signer:: Signer as ExtendedSigner ;
25+ use self :: signer:: { ContractCall , ExtendedMiddleware , ExtendedSigner } ;
2626use self :: walletconnect:: WalletConnect ;
2727
2828/// Radicle's ENS domain.
@@ -32,6 +32,7 @@ pub const SIGNER_OPTIONS: &str = r#"
3232 --ledger-hdpath <hdpath> Account derivation path when using a Ledger hardware device
3333 --keystore <file> Keystore file containing encrypted private key (default: none)
3434 --walletconnect Use WalletConnect
35+ --legacy Send transactions in legacy mode
3536"# ;
3637
3738pub const PROVIDER_OPTIONS : & str = r#"
@@ -52,6 +53,8 @@ pub struct SignerOptions {
5253 pub keystore : Option < PathBuf > ,
5354 /// Walletconnect account (default: false).
5455 pub walletconnect : bool ,
56+ /// Legacy transaction (default: false).
57+ pub legacy : bool ,
5558}
5659
5760impl SignerOptions {
@@ -65,6 +68,7 @@ impl SignerOptions {
6568 . ok ( )
6669 . and_then ( |v| DerivationPath :: from_str ( v. as_str ( ) ) . ok ( ) ) ,
6770 walletconnect : false ,
71+ legacy : false ,
6872 } ;
6973
7074 while let Some ( arg) = parser. next ( ) ? {
@@ -85,7 +89,7 @@ impl SignerOptions {
8589 options. walletconnect = true ;
8690 }
8791 Long ( "legacy" ) => {
88- std :: env :: set_var ( "RAD_SIGNER_LEGACY" , " true" ) ;
92+ options . legacy = true ;
8993 }
9094 _ => unparsed. push ( args:: format ( arg) ) ,
9195 }
@@ -161,96 +165,143 @@ pub enum Wallet {
161165 WalletConnect ( WalletConnect ) ,
162166}
163167
168+ #[ derive( Debug ) ]
169+ pub enum TypedWallet {
170+ Legacy ( Wallet ) ,
171+ Modern ( Wallet ) ,
172+ }
173+
174+ impl TypedWallet {
175+ fn wallet ( & self ) -> & Wallet {
176+ match self {
177+ Self :: Legacy ( wallet) => wallet,
178+ Self :: Modern ( wallet) => wallet,
179+ }
180+ }
181+
182+ fn own_wallet ( self ) -> Wallet {
183+ match self {
184+ Self :: Legacy ( wallet) => wallet,
185+ Self :: Modern ( wallet) => wallet,
186+ }
187+ }
188+
189+ fn wrapper ( & self ) -> fn ( Wallet ) -> Self {
190+ match self {
191+ Self :: Legacy ( _) => Self :: Legacy ,
192+ Self :: Modern ( _) => Self :: Modern ,
193+ }
194+ }
195+ }
196+
164197#[ async_trait:: async_trait]
165- impl ExtendedSigner for Wallet {
198+ impl Signer for TypedWallet {
166199 type Error = WalletError ;
167200
168201 fn chain_id ( & self ) -> u64 {
169- match self {
170- Self :: Ledger ( s) => s. chain_id ( ) ,
171- Self :: Local ( s) => s. chain_id ( ) ,
172- Self :: WalletConnect ( s) => s. chain_id ( ) ,
202+ match self . wallet ( ) {
203+ Wallet :: Ledger ( s) => s. chain_id ( ) ,
204+ Wallet :: Local ( s) => s. chain_id ( ) ,
205+ Wallet :: WalletConnect ( s) => s. chain_id ( ) ,
173206 }
174207 }
175208
176209 fn address ( & self ) -> Address {
177- match self {
178- Self :: Ledger ( s) => s. address ( ) ,
179- Self :: Local ( s) => s. address ( ) ,
180- Self :: WalletConnect ( s) => s. address ( ) ,
210+ match self . wallet ( ) {
211+ Wallet :: Ledger ( s) => s. address ( ) ,
212+ Wallet :: Local ( s) => s. address ( ) ,
213+ Wallet :: WalletConnect ( s) => s. address ( ) ,
181214 }
182215 }
183216
184217 fn with_chain_id < T : Into < u64 > > ( self , chain_id : T ) -> Self {
185- match self {
186- Self :: Ledger ( s) => Self :: Ledger ( s. with_chain_id ( chain_id) ) ,
187- Self :: Local ( s) => Self :: Local ( s. with_chain_id ( chain_id) ) ,
188- Self :: WalletConnect ( _s) => unimplemented ! ( ) ,
218+ let wrapper = self . wrapper ( ) ;
219+ match self . own_wallet ( ) {
220+ Wallet :: Ledger ( s) => ( wrapper) ( Wallet :: Ledger ( s. with_chain_id ( chain_id) ) ) ,
221+ Wallet :: Local ( s) => ( wrapper) ( Wallet :: Local ( s. with_chain_id ( chain_id) ) ) ,
222+ Wallet :: WalletConnect ( _s) => unimplemented ! ( ) ,
189223 }
190224 }
191225
192226 async fn sign_typed_data < T : Eip712 + Send + Sync > (
193227 & self ,
194228 payload : & T ,
195229 ) -> Result < Signature , Self :: Error > {
196- match self {
197- Self :: Ledger ( s) => s. sign_typed_data ( payload) . await . map_err ( WalletError :: from) ,
198- Self :: Local ( s) => s. sign_typed_data ( payload) . await . map_err ( WalletError :: from) ,
199- Self :: WalletConnect ( _s) => unimplemented ! ( ) ,
230+ match self . wallet ( ) {
231+ Wallet :: Ledger ( s) => s. sign_typed_data ( payload) . await . map_err ( WalletError :: from) ,
232+ Wallet :: Local ( s) => s. sign_typed_data ( payload) . await . map_err ( WalletError :: from) ,
233+ Wallet :: WalletConnect ( _s) => unimplemented ! ( ) ,
200234 }
201235 }
202236
203237 async fn sign_message < S : Send + Sync + AsRef < [ u8 ] > > (
204238 & self ,
205239 message : S ,
206240 ) -> Result < Signature , Self :: Error > {
207- match self {
208- Self :: Ledger ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
209- Self :: Local ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
210- Self :: WalletConnect ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
241+ match self . wallet ( ) {
242+ Wallet :: Ledger ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
243+ Wallet :: Local ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
244+ Wallet :: WalletConnect ( s) => s. sign_message ( message) . await . map_err ( WalletError :: from) ,
211245 }
212246 }
213247
214248 async fn sign_transaction (
215249 & self ,
216250 message : & ethers:: types:: transaction:: eip2718:: TypedTransaction ,
217251 ) -> Result < Signature , Self :: Error > {
218- match self {
219- Self :: Ledger ( s) => s. sign_transaction ( message) . await . map_err ( WalletError :: from) ,
220- Self :: Local ( s) => s. sign_transaction ( message) . await . map_err ( WalletError :: from) ,
221- Self :: WalletConnect ( s) => s. sign_transaction ( message) . await . map_err ( WalletError :: from) ,
252+ match self . wallet ( ) {
253+ Wallet :: Ledger ( s) => s. sign_transaction ( message) . await . map_err ( WalletError :: from) ,
254+ Wallet :: Local ( s) => s. sign_transaction ( message) . await . map_err ( WalletError :: from) ,
255+ Wallet :: WalletConnect ( s) => {
256+ s. sign_transaction ( message) . await . map_err ( WalletError :: from)
257+ }
222258 }
223259 }
260+ }
224261
262+ #[ async_trait:: async_trait]
263+ impl ExtendedSigner for TypedWallet {
225264 async fn send_transaction (
226265 & self ,
227266 message : & ethers:: types:: transaction:: eip2718:: TypedTransaction ,
228267 ) -> Result < H256 , Self :: Error > {
229- match self {
230- Self :: Ledger ( _) => unimplemented ! ( ) ,
231- Self :: Local ( _) => unimplemented ! ( ) ,
232- Self :: WalletConnect ( s) => s. send_transaction ( message) . await . map_err ( WalletError :: from) ,
268+ match self . wallet ( ) {
269+ Wallet :: Ledger ( _) => unimplemented ! ( ) ,
270+ Wallet :: Local ( _) => unimplemented ! ( ) ,
271+ Wallet :: WalletConnect ( s) => {
272+ s. send_transaction ( message) . await . map_err ( WalletError :: from)
273+ }
233274 }
234275 }
235276
236277 fn is_walletconnect ( & self ) -> bool {
278+ match self . wallet ( ) {
279+ Wallet :: Ledger ( _) => false ,
280+ Wallet :: Local ( _) => false ,
281+ Wallet :: WalletConnect ( _) => true ,
282+ }
283+ }
284+
285+ fn is_legacy ( & self ) -> bool {
237286 match self {
238- Self :: Ledger ( _) => false ,
239- Self :: Local ( _) => false ,
240- Self :: WalletConnect ( _) => true ,
287+ Self :: Legacy ( _) => true ,
288+ Self :: Modern ( _) => false ,
241289 }
242290 }
243291}
244292
245293impl Wallet {
246294 /// Open a wallet from the given options and provider.
247- pub async fn open < P > ( options : SignerOptions , provider : Provider < P > ) -> anyhow:: Result < Wallet >
295+ pub async fn open < P > (
296+ options : SignerOptions ,
297+ provider : Provider < P > ,
298+ ) -> anyhow:: Result < TypedWallet >
248299 where
249300 P : JsonRpcClient + Clone + ' static ,
250301 {
251302 let chain_id = provider. get_chainid ( ) . await ?. as_u64 ( ) ;
252303
253- if let Some ( keypath) = & options. keystore {
304+ let wallet = if let Some ( keypath) = & options. keystore {
254305 let password = term:: secret_input_with_prompt ( "Keystore password" ) ;
255306 let spinner = term:: spinner ( "Decrypting keystore..." ) ;
256307 let signer = LocalWallet :: decrypt_keystore ( keypath, password. unsecure ( ) )
@@ -277,6 +328,12 @@ impl Wallet {
277328 Ok ( Wallet :: WalletConnect ( signer) )
278329 } else {
279330 Err ( WalletError :: NoWallet . into ( ) )
331+ } ;
332+
333+ if options. legacy {
334+ wallet. map ( TypedWallet :: Legacy )
335+ } else {
336+ wallet. map ( TypedWallet :: Modern )
280337 }
281338 }
282339}
@@ -285,13 +342,9 @@ impl Wallet {
285342pub async fn transaction < M , D > ( call : ContractCall < M , D > ) -> anyhow:: Result < TransactionReceipt >
286343where
287344 D : Detokenize ,
288- M : Middleware + ' static ,
345+ M : ExtendedMiddleware + ' static ,
289346{
290- let call = if std:: env:: var_os ( "RAD_SIGNER_LEGACY" ) . is_some ( ) {
291- call. legacy ( )
292- } else {
293- call
294- } ;
347+ let call = call. set_tx_type ( ) ;
295348 let receipt = loop {
296349 let spinner = term:: spinner ( "Waiting for transaction to be signed..." ) ;
297350 let tx = match call. send ( ) . await {
@@ -348,7 +401,7 @@ pub fn hex(bytes: impl AsRef<[u8]>) -> String {
348401pub async fn get_wallet (
349402 signer_opts : SignerOptions ,
350403 provider : Provider < Http > ,
351- ) -> anyhow:: Result < ( Wallet , Provider < Http > ) > {
404+ ) -> anyhow:: Result < ( TypedWallet , Provider < Http > ) > {
352405 use rad_terminal:: args:: Error ;
353406
354407 term:: tip!( "Accessing your wallet..." ) ;
0 commit comments