35
35
#![ cfg_attr( not( feature = "std" ) , no_std) ]
36
36
37
37
use sp_std:: prelude:: * ;
38
- use frame_support:: { decl_module, decl_event, decl_error, decl_storage, Parameter , ensure} ;
38
+ use codec:: { Encode , Decode } ;
39
+ use sp_io:: hashing:: blake2_256;
40
+ use sp_runtime:: { DispatchResult , traits:: { Dispatchable , Zero } } ;
41
+ use sp_runtime:: traits:: Member ;
39
42
use frame_support:: {
43
+ decl_module, decl_event, decl_error, decl_storage, Parameter , ensure,
40
44
traits:: { Get , ReservableCurrency , Currency , Filter , InstanceFilter } ,
41
45
weights:: { GetDispatchInfo , constants:: { WEIGHT_PER_MICROS , WEIGHT_PER_NANOS } } ,
42
46
dispatch:: { PostDispatchInfo , IsSubType } ,
43
47
} ;
44
48
use frame_system:: { self as system, ensure_signed} ;
45
- use sp_runtime:: { DispatchResult , traits:: { Dispatchable , Zero } } ;
46
- use sp_runtime:: traits:: Member ;
47
49
48
50
mod tests;
49
51
mod benchmarking;
@@ -53,7 +55,7 @@ type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trai
53
55
/// Configuration trait.
54
56
pub trait Trait : frame_system:: Trait {
55
57
/// The overarching event type.
56
- type Event : From < Event > + Into < <Self as frame_system:: Trait >:: Event > ;
58
+ type Event : From < Event < Self > > + Into < <Self as frame_system:: Trait >:: Event > ;
57
59
58
60
/// The overarching call type.
59
61
type Call : Parameter + Dispatchable < Origin =Self :: Origin , PostInfo =PostDispatchInfo >
@@ -115,9 +117,15 @@ decl_error! {
115
117
116
118
decl_event ! {
117
119
/// Events type.
118
- pub enum Event {
120
+ pub enum Event <T > where
121
+ AccountId = <T as frame_system:: Trait >:: AccountId ,
122
+ ProxyType = <T as Trait >:: ProxyType
123
+ {
119
124
/// A proxy was executed correctly, with the given result.
120
125
ProxyExecuted ( DispatchResult ) ,
126
+ /// Anonymous account (first parameter) has been created by new proxy (second) with given
127
+ /// disambiguation index and proxy type.
128
+ AnonymousCreated ( AccountId , AccountId , ProxyType , u16 ) ,
121
129
}
122
130
}
123
131
@@ -164,12 +172,12 @@ decl_module! {
164
172
. ok_or( Error :: <T >:: NotProxy ) ?;
165
173
match call. is_sub_type( ) {
166
174
Some ( Call :: add_proxy( _, ref pt) ) | Some ( Call :: remove_proxy( _, ref pt) ) =>
167
- ensure!( & proxy_type == pt , Error :: <T >:: NoPermission ) ,
175
+ ensure!( pt . is_no_more_permissive ( & proxy_type) , Error :: <T >:: NoPermission ) ,
168
176
_ => ( ) ,
169
177
}
170
178
ensure!( proxy_type. filter( & call) , Error :: <T >:: Unproxyable ) ;
171
179
let e = call. dispatch( frame_system:: RawOrigin :: Signed ( real) . into( ) ) ;
172
- Self :: deposit_event( Event :: ProxyExecuted ( e. map( |_| ( ) ) . map_err( |e| e. error) ) ) ;
180
+ Self :: deposit_event( RawEvent :: ProxyExecuted ( e. map( |_| ( ) ) . map_err( |e| e. error) ) ) ;
173
181
}
174
182
175
183
/// Register a proxy account for the sender that is able to make calls on its behalf.
@@ -186,8 +194,8 @@ decl_module! {
186
194
/// - DB weight: 1 storage read and write.
187
195
/// # </weight>
188
196
#[ weight = T :: DbWeight :: get( ) . reads_writes( 1 , 1 )
189
- . saturating_add( 18 * WEIGHT_PER_MICROS )
190
- . saturating_add( ( 200 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
197
+ . saturating_add( 18 * WEIGHT_PER_MICROS )
198
+ . saturating_add( ( 200 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
191
199
]
192
200
fn add_proxy( origin, proxy: T :: AccountId , proxy_type: T :: ProxyType ) -> DispatchResult {
193
201
let who = ensure_signed( origin) ?;
@@ -222,8 +230,8 @@ decl_module! {
222
230
/// - DB weight: 1 storage read and write.
223
231
/// # </weight>
224
232
#[ weight = T :: DbWeight :: get( ) . reads_writes( 1 , 1 )
225
- . saturating_add( 14 * WEIGHT_PER_MICROS )
226
- . saturating_add( ( 160 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
233
+ . saturating_add( 14 * WEIGHT_PER_MICROS )
234
+ . saturating_add( ( 160 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
227
235
]
228
236
fn remove_proxy( origin, proxy: T :: AccountId , proxy_type: T :: ProxyType ) -> DispatchResult {
229
237
let who = ensure_signed( origin) ?;
@@ -253,19 +261,119 @@ decl_module! {
253
261
///
254
262
/// The dispatch origin for this call must be _Signed_.
255
263
///
264
+ /// WARNING: This may be called on accounts created by `anonymous`, however if done, then
265
+ /// the unreserved fees will be inaccessible. **All access to this account will be lost.**
266
+ ///
256
267
/// # <weight>
257
268
/// P is the number of proxies the user has
258
269
/// - Base weight: 13.73 + .129 * P µs
259
270
/// - DB weight: 1 storage read and write.
260
271
/// # </weight>
261
272
#[ weight = T :: DbWeight :: get( ) . reads_writes( 1 , 1 )
262
- . saturating_add( 14 * WEIGHT_PER_MICROS )
263
- . saturating_add( ( 130 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
273
+ . saturating_add( 14 * WEIGHT_PER_MICROS )
274
+ . saturating_add( ( 130 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
264
275
]
265
276
fn remove_proxies( origin) {
266
277
let who = ensure_signed( origin) ?;
267
278
let ( _, old_deposit) = Proxies :: <T >:: take( & who) ;
268
279
T :: Currency :: unreserve( & who, old_deposit) ;
269
280
}
281
+
282
+ /// Spawn a fresh new account that is guaranteed to be otherwise inaccessible, and
283
+ /// initialize it with a proxy of `proxy_type` for `origin` sender.
284
+ ///
285
+ /// Requires a `Signed` origin.
286
+ ///
287
+ /// - `proxy_type`: The type of the proxy that the sender will be registered as over the
288
+ /// new account. This will almost always be the most permissive `ProxyType` possible to
289
+ /// allow for maximum flexibility.
290
+ /// - `index`: A disambiguation index, in case this is called multiple times in the same
291
+ /// transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just
292
+ /// want to use `0`.
293
+ ///
294
+ /// Fails with `Duplicate` if this has already been called in this transaction, from the
295
+ /// same sender, with the same parameters.
296
+ ///
297
+ /// Fails if there are insufficient funds to pay for deposit.
298
+ ///
299
+ /// # <weight>
300
+ /// P is the number of proxies the user has
301
+ /// - Base weight: 36.48 + .039 * P µs
302
+ /// - DB weight: 1 storage read and write.
303
+ /// # </weight>
304
+ #[ weight = T :: DbWeight :: get( ) . reads_writes( 1 , 1 )
305
+ . saturating_add( 36 * WEIGHT_PER_MICROS )
306
+ . saturating_add( ( 40 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
307
+ ]
308
+ fn anonymous( origin, proxy_type: T :: ProxyType , index: u16 ) {
309
+ let who = ensure_signed( origin) ?;
310
+
311
+ let anonymous = Self :: anonymous_account( & who, & proxy_type, index, None ) ;
312
+ ensure!( !Proxies :: <T >:: contains_key( & anonymous) , Error :: <T >:: Duplicate ) ;
313
+ let deposit = T :: ProxyDepositBase :: get( ) + T :: ProxyDepositFactor :: get( ) ;
314
+ T :: Currency :: reserve( & who, deposit) ?;
315
+ Proxies :: <T >:: insert( & anonymous, ( vec![ ( who. clone( ) , proxy_type. clone( ) ) ] , deposit) ) ;
316
+ Self :: deposit_event( RawEvent :: AnonymousCreated ( anonymous, who, proxy_type, index) ) ;
317
+ }
318
+
319
+ /// Removes a previously spawned anonymous proxy.
320
+ ///
321
+ /// WARNING: **All access to this account will be lost.** Any funds held in it will be
322
+ /// inaccessible.
323
+ ///
324
+ /// Requires a `Signed` origin, and the sender account must have been created by a call to
325
+ /// `anonymous` with corresponding parameters.
326
+ ///
327
+ /// - `spawner`: The account that originally called `anonymous` to create this account.
328
+ /// - `index`: The disambiguation index originally passed to `anonymous`. Probably `0`.
329
+ /// - `proxy_type`: The proxy type originally passed to `anonymous`.
330
+ /// - `height`: The height of the chain when the call to `anonymous` was processed.
331
+ /// - `ext_index`: The extrinsic index in which the call to `anonymous` was processed.
332
+ ///
333
+ /// Fails with `NoPermission` in case the caller is not a previously created anonymous
334
+ /// account whose `anonymous` call has corresponding parameters.
335
+ ///
336
+ /// # <weight>
337
+ /// P is the number of proxies the user has
338
+ /// - Base weight: 15.65 + .137 * P µs
339
+ /// - DB weight: 1 storage read and write.
340
+ /// # </weight>
341
+ #[ weight = T :: DbWeight :: get( ) . reads_writes( 1 , 1 )
342
+ . saturating_add( 15 * WEIGHT_PER_MICROS )
343
+ . saturating_add( ( 140 * WEIGHT_PER_NANOS ) . saturating_mul( T :: MaxProxies :: get( ) . into( ) ) )
344
+ ]
345
+ fn kill_anonymous( origin,
346
+ spawner: T :: AccountId ,
347
+ proxy_type: T :: ProxyType ,
348
+ index: u16 ,
349
+ #[ compact] height: T :: BlockNumber ,
350
+ #[ compact] ext_index: u32 ,
351
+ ) {
352
+ let who = ensure_signed( origin) ?;
353
+
354
+ let when = ( height, ext_index) ;
355
+ let proxy = Self :: anonymous_account( & spawner, & proxy_type, index, Some ( when) ) ;
356
+ ensure!( proxy == who, Error :: <T >:: NoPermission ) ;
357
+
358
+ let ( _, deposit) = Proxies :: <T >:: take( & who) ;
359
+ T :: Currency :: unreserve( & spawner, deposit) ;
360
+ }
361
+ }
362
+ }
363
+
364
+ impl < T : Trait > Module < T > {
365
+ pub fn anonymous_account (
366
+ who : & T :: AccountId ,
367
+ proxy_type : & T :: ProxyType ,
368
+ index : u16 ,
369
+ maybe_when : Option < ( T :: BlockNumber , u32 ) > ,
370
+ ) -> T :: AccountId {
371
+ let ( height, ext_index) = maybe_when. unwrap_or_else ( || (
372
+ system:: Module :: < T > :: block_number ( ) ,
373
+ system:: Module :: < T > :: extrinsic_index ( ) . unwrap_or_default ( )
374
+ ) ) ;
375
+ let entropy = ( b"modlpy/proxy____" , who, height, ext_index, proxy_type, index)
376
+ . using_encoded ( blake2_256) ;
377
+ T :: AccountId :: decode ( & mut & entropy[ ..] ) . unwrap_or_default ( )
270
378
}
271
379
}
0 commit comments