1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! # Multisig pallet
19
//! A pallet for doing multisig dispatch.
20
//!
21
//! - [`Config`]
22
//! - [`Call`]
23
//!
24
//! ## Overview
25
//!
26
//! This pallet contains functionality for multi-signature dispatch, a (potentially) stateful
27
//! operation, allowing multiple signed
28
//! origins (accounts) to coordinate and dispatch a call from a well-known origin, derivable
29
//! deterministically from the set of account IDs and the threshold number of accounts from the
30
//! set that must approve it. In the case that the threshold is just one then this is a stateless
31
//! operation. This is useful for multisig wallets where cryptographic threshold signatures are
32
//! not available or desired.
33
//!
34
//! ## Interface
35
//!
36
//! ### Dispatchable Functions
37
//!
38
//! * `as_multi` - Approve and if possible dispatch a call from a composite origin formed from a
39
//!   number of signed origins.
40
//! * `approve_as_multi` - Approve a call from a composite origin.
41
//! * `cancel_as_multi` - Cancel a call from a composite origin.
42

            
43
// Ensure we're `no_std` when compiling for Wasm.
44
#![cfg_attr(not(feature = "std"), no_std)]
45

            
46
mod benchmarking;
47
pub mod migrations;
48
mod tests;
49
pub mod weights;
50

            
51
extern crate alloc;
52

            
53
use alloc::{boxed::Box, vec, vec::Vec};
54
use codec::{Decode, Encode, MaxEncodedLen};
55
use frame_support::{
56
	dispatch::{
57
		DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
58
		PostDispatchInfo,
59
	},
60
	ensure,
61
	traits::{Currency, Get, ReservableCurrency},
62
	weights::Weight,
63
	BoundedVec,
64
};
65
use frame_system::{self as system, pallet_prelude::BlockNumberFor, RawOrigin};
66
use scale_info::TypeInfo;
67
use sp_io::hashing::blake2_256;
68
use sp_runtime::{
69
	traits::{Dispatchable, TrailingZeroInput, Zero},
70
	DispatchError, RuntimeDebug,
71
};
72
pub use weights::WeightInfo;
73

            
74
pub use pallet::*;
75

            
76
/// The log target of this pallet.
77
pub const LOG_TARGET: &'static str = "runtime::multisig";
78

            
79
// syntactic sugar for logging.
80
#[macro_export]
81
macro_rules! log {
82
	($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
83
		log::$level!(
84
			target: crate::LOG_TARGET,
85
			concat!("[{:?}] ✍️ ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
86
		)
87
	};
88
}
89

            
90
type BalanceOf<T> =
91
	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
92

            
93
/// A global extrinsic index, formed as the extrinsic index within a block, together with that
94
/// block's height. This allows a transaction in which a multisig operation of a particular
95
/// composite was created to be uniquely identified.
96
#[derive(
97
	Copy, Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen,
98
)]
99
pub struct Timepoint<BlockNumber> {
100
	/// The height of the chain at the point in time.
101
	height: BlockNumber,
102
	/// The index of the extrinsic at the point in time.
103
	index: u32,
104
}
105

            
106
/// An open multisig operation.
107
#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)]
108
#[scale_info(skip_type_params(MaxApprovals))]
109
pub struct Multisig<BlockNumber, Balance, AccountId, MaxApprovals>
110
where
111
	MaxApprovals: Get<u32>,
112
{
113
	/// The extrinsic when the multisig operation was opened.
114
	when: Timepoint<BlockNumber>,
115
	/// The amount held in reserve of the `depositor`, to be returned once the operation ends.
116
	deposit: Balance,
117
	/// The account who opened it (i.e. the first to approve it).
118
	depositor: AccountId,
119
	/// The approvals achieved so far, including the depositor. Always sorted.
120
	approvals: BoundedVec<AccountId, MaxApprovals>,
121
}
122

            
123
type CallHash = [u8; 32];
124

            
125
enum CallOrHash<T: Config> {
126
	Call(<T as Config>::RuntimeCall),
127
	Hash([u8; 32]),
128
}
129

            
130
31591
#[frame_support::pallet]
131
pub mod pallet {
132
	use super::*;
133
	use frame_support::pallet_prelude::*;
134
	use frame_system::pallet_prelude::*;
135

            
136
	#[pallet::config]
137
	pub trait Config: frame_system::Config {
138
		/// The overarching event type.
139
		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
140

            
141
		/// The overarching call type.
142
		type RuntimeCall: Parameter
143
			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
144
			+ GetDispatchInfo
145
			+ From<frame_system::Call<Self>>;
146

            
147
		/// The currency mechanism.
148
		type Currency: ReservableCurrency<Self::AccountId>;
149

            
150
		/// The base amount of currency needed to reserve for creating a multisig execution or to
151
		/// store a dispatch call for later.
152
		///
153
		/// This is held for an additional storage item whose value size is
154
		/// `4 + sizeof((BlockNumber, Balance, AccountId))` bytes and whose key size is
155
		/// `32 + sizeof(AccountId)` bytes.
156
		#[pallet::constant]
157
		type DepositBase: Get<BalanceOf<Self>>;
158

            
159
		/// The amount of currency needed per unit threshold when creating a multisig execution.
160
		///
161
		/// This is held for adding 32 bytes more into a pre-existing storage value.
162
		#[pallet::constant]
163
		type DepositFactor: Get<BalanceOf<Self>>;
164

            
165
		/// The maximum amount of signatories allowed in the multisig.
166
		#[pallet::constant]
167
		type MaxSignatories: Get<u32>;
168

            
169
		/// Weight information for extrinsics in this pallet.
170
		type WeightInfo: WeightInfo;
171
	}
172

            
173
	/// The in-code storage version.
174
	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
175

            
176
1698
	#[pallet::pallet]
177
	#[pallet::storage_version(STORAGE_VERSION)]
178
	pub struct Pallet<T>(_);
179

            
180
	/// The set of open multisig operations.
181
636
	#[pallet::storage]
182
	pub type Multisigs<T: Config> = StorageDoubleMap<
183
		_,
184
		Twox64Concat,
185
		T::AccountId,
186
		Blake2_128Concat,
187
		[u8; 32],
188
		Multisig<BlockNumberFor<T>, BalanceOf<T>, T::AccountId, T::MaxSignatories>,
189
	>;
190

            
191
60786
	#[pallet::error]
192
	pub enum Error<T> {
193
		/// Threshold must be 2 or greater.
194
		MinimumThreshold,
195
		/// Call is already approved by this signatory.
196
		AlreadyApproved,
197
		/// Call doesn't need any (more) approvals.
198
		NoApprovalsNeeded,
199
		/// There are too few signatories in the list.
200
		TooFewSignatories,
201
		/// There are too many signatories in the list.
202
		TooManySignatories,
203
		/// The signatories were provided out of order; they should be ordered.
204
		SignatoriesOutOfOrder,
205
		/// The sender was contained in the other signatories; it shouldn't be.
206
		SenderInSignatories,
207
		/// Multisig operation not found when attempting to cancel.
208
		NotFound,
209
		/// Only the account that originally created the multisig is able to cancel it.
210
		NotOwner,
211
		/// No timepoint was given, yet the multisig operation is already underway.
212
		NoTimepoint,
213
		/// A different timepoint was given to the multisig operation that is underway.
214
		WrongTimepoint,
215
		/// A timepoint was given, yet no multisig operation is underway.
216
		UnexpectedTimepoint,
217
		/// The maximum weight information provided was too low.
218
		MaxWeightTooLow,
219
		/// The data to be stored is already stored.
220
		AlreadyStored,
221
	}
222

            
223
	#[pallet::event]
224
288
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
225
	pub enum Event<T: Config> {
226
		/// A new multisig operation has begun.
227
		NewMultisig { approving: T::AccountId, multisig: T::AccountId, call_hash: CallHash },
228
		/// A multisig operation has been approved by someone.
229
		MultisigApproval {
230
			approving: T::AccountId,
231
			timepoint: Timepoint<BlockNumberFor<T>>,
232
			multisig: T::AccountId,
233
			call_hash: CallHash,
234
		},
235
		/// A multisig operation has been executed.
236
		MultisigExecuted {
237
			approving: T::AccountId,
238
			timepoint: Timepoint<BlockNumberFor<T>>,
239
			multisig: T::AccountId,
240
			call_hash: CallHash,
241
			result: DispatchResult,
242
		},
243
		/// A multisig operation has been cancelled.
244
		MultisigCancelled {
245
			cancelling: T::AccountId,
246
			timepoint: Timepoint<BlockNumberFor<T>>,
247
			multisig: T::AccountId,
248
			call_hash: CallHash,
249
		},
250
	}
251

            
252
554367
	#[pallet::hooks]
253
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
254

            
255
287487
	#[pallet::call]
256
	impl<T: Config> Pallet<T> {
257
		/// Immediately dispatch a multi-signature call using a single approval from the caller.
258
		///
259
		/// The dispatch origin for this call must be _Signed_.
260
		///
261
		/// - `other_signatories`: The accounts (other than the sender) who are part of the
262
		/// multi-signature, but do not participate in the approval process.
263
		/// - `call`: The call to be executed.
264
		///
265
		/// Result is equivalent to the dispatched result.
266
		///
267
		/// ## Complexity
268
		/// O(Z + C) where Z is the length of the call and C its execution weight.
269
		#[pallet::call_index(0)]
270
		#[pallet::weight({
271
			let dispatch_info = call.get_dispatch_info();
272
			(
273
104694
				T::WeightInfo::as_multi_threshold_1(call.using_encoded(|c| c.len() as u32))
274
					// AccountData for inner call origin accountdata.
275
					.saturating_add(T::DbWeight::get().reads_writes(1, 1))
276
					.saturating_add(dispatch_info.weight),
277
				dispatch_info.class,
278
			)
279
		})]
280
		pub fn as_multi_threshold_1(
281
			origin: OriginFor<T>,
282
			other_signatories: Vec<T::AccountId>,
283
			call: Box<<T as Config>::RuntimeCall>,
284
29682
		) -> DispatchResultWithPostInfo {
285
29682
			let who = ensure_signed(origin)?;
286
29682
			let max_sigs = T::MaxSignatories::get() as usize;
287
29682
			ensure!(!other_signatories.is_empty(), Error::<T>::TooFewSignatories);
288
1179
			let other_signatories_len = other_signatories.len();
289
1179
			ensure!(other_signatories_len < max_sigs, Error::<T>::TooManySignatories);
290
1179
			let signatories = Self::ensure_sorted_and_insert(other_signatories, who)?;
291

            
292
861
			let id = Self::multi_account_id(&signatories, 1);
293
861

            
294
1148
			let call_len = call.using_encoded(|c| c.len());
295
861
			let result = call.dispatch(RawOrigin::Signed(id).into());
296
861

            
297
861
			result
298
861
				.map(|post_dispatch_info| {
299
51
					post_dispatch_info
300
51
						.actual_weight
301
51
						.map(|actual_weight| {
302
21
							T::WeightInfo::as_multi_threshold_1(call_len as u32)
303
21
								.saturating_add(actual_weight)
304
51
						})
305
51
						.into()
306
861
				})
307
861
				.map_err(|err| match err.post_info.actual_weight {
308
42
					Some(actual_weight) => {
309
42
						let weight_used = T::WeightInfo::as_multi_threshold_1(call_len as u32)
310
42
							.saturating_add(actual_weight);
311
42
						let post_info = Some(weight_used).into();
312
42
						DispatchErrorWithPostInfo { post_info, error: err.error }
313
					},
314
768
					None => err,
315
861
				})
316
		}
317

            
318
		/// Register approval for a dispatch to be made from a deterministic composite account if
319
		/// approved by a total of `threshold - 1` of `other_signatories`.
320
		///
321
		/// If there are enough, then dispatch the call.
322
		///
323
		/// Payment: `DepositBase` will be reserved if this is the first approval, plus
324
		/// `threshold` times `DepositFactor`. It is returned once this dispatch happens or
325
		/// is cancelled.
326
		///
327
		/// The dispatch origin for this call must be _Signed_.
328
		///
329
		/// - `threshold`: The total number of approvals for this dispatch before it is executed.
330
		/// - `other_signatories`: The accounts (other than the sender) who can approve this
331
		/// dispatch. May not be empty.
332
		/// - `maybe_timepoint`: If this is the first approval, then this must be `None`. If it is
333
		/// not the first approval, then it must be `Some`, with the timepoint (block number and
334
		/// transaction index) of the first approval transaction.
335
		/// - `call`: The call to be executed.
336
		///
337
		/// NOTE: Unless this is the final approval, you will generally want to use
338
		/// `approve_as_multi` instead, since it only requires a hash of the call.
339
		///
340
		/// Result is equivalent to the dispatched result if `threshold` is exactly `1`. Otherwise
341
		/// on success, result is `Ok` and the result from the interior call, if it was executed,
342
		/// may be found in the deposited `MultisigExecuted` event.
343
		///
344
		/// ## Complexity
345
		/// - `O(S + Z + Call)`.
346
		/// - Up to one balance-reserve or unreserve operation.
347
		/// - One passthrough operation, one insert, both `O(S)` where `S` is the number of
348
		///   signatories. `S` is capped by `MaxSignatories`, with weight being proportional.
349
		/// - One call encode & hash, both of complexity `O(Z)` where `Z` is tx-len.
350
		/// - One encode & hash, both of complexity `O(S)`.
351
		/// - Up to one binary search and insert (`O(logS + S)`).
352
		/// - I/O: 1 read `O(S)`, up to 1 mutate `O(S)`. Up to one remove.
353
		/// - One event.
354
		/// - The weight of the `call`.
355
		/// - Storage: inserts one item, value size bounded by `MaxSignatories`, with a deposit
356
		///   taken for its lifetime of `DepositBase + threshold * DepositFactor`.
357
		#[pallet::call_index(1)]
358
		#[pallet::weight({
359
			let s = other_signatories.len() as u32;
360
2676
			let z = call.using_encoded(|d| d.len()) as u32;
361

            
362
			T::WeightInfo::as_multi_create(s, z)
363
			.max(T::WeightInfo::as_multi_approve(s, z))
364
			.max(T::WeightInfo::as_multi_complete(s, z))
365
			.saturating_add(*max_weight)
366
		})]
367
		pub fn as_multi(
368
			origin: OriginFor<T>,
369
			threshold: u16,
370
			other_signatories: Vec<T::AccountId>,
371
			maybe_timepoint: Option<Timepoint<BlockNumberFor<T>>>,
372
			call: Box<<T as Config>::RuntimeCall>,
373
			max_weight: Weight,
374
1530
		) -> DispatchResultWithPostInfo {
375
1530
			let who = ensure_signed(origin)?;
376
1530
			Self::operate(
377
1530
				who,
378
1530
				threshold,
379
1530
				other_signatories,
380
1530
				maybe_timepoint,
381
1530
				CallOrHash::Call(*call),
382
1530
				max_weight,
383
1530
			)
384
		}
385

            
386
		/// Register approval for a dispatch to be made from a deterministic composite account if
387
		/// approved by a total of `threshold - 1` of `other_signatories`.
388
		///
389
		/// Payment: `DepositBase` will be reserved if this is the first approval, plus
390
		/// `threshold` times `DepositFactor`. It is returned once this dispatch happens or
391
		/// is cancelled.
392
		///
393
		/// The dispatch origin for this call must be _Signed_.
394
		///
395
		/// - `threshold`: The total number of approvals for this dispatch before it is executed.
396
		/// - `other_signatories`: The accounts (other than the sender) who can approve this
397
		/// dispatch. May not be empty.
398
		/// - `maybe_timepoint`: If this is the first approval, then this must be `None`. If it is
399
		/// not the first approval, then it must be `Some`, with the timepoint (block number and
400
		/// transaction index) of the first approval transaction.
401
		/// - `call_hash`: The hash of the call to be executed.
402
		///
403
		/// NOTE: If this is the final approval, you will want to use `as_multi` instead.
404
		///
405
		/// ## Complexity
406
		/// - `O(S)`.
407
		/// - Up to one balance-reserve or unreserve operation.
408
		/// - One passthrough operation, one insert, both `O(S)` where `S` is the number of
409
		///   signatories. `S` is capped by `MaxSignatories`, with weight being proportional.
410
		/// - One encode & hash, both of complexity `O(S)`.
411
		/// - Up to one binary search and insert (`O(logS + S)`).
412
		/// - I/O: 1 read `O(S)`, up to 1 mutate `O(S)`. Up to one remove.
413
		/// - One event.
414
		/// - Storage: inserts one item, value size bounded by `MaxSignatories`, with a deposit
415
		///   taken for its lifetime of `DepositBase + threshold * DepositFactor`.
416
		#[pallet::call_index(2)]
417
		#[pallet::weight({
418
			let s = other_signatories.len() as u32;
419

            
420
			T::WeightInfo::approve_as_multi_create(s)
421
				.max(T::WeightInfo::approve_as_multi_approve(s))
422
				.saturating_add(*max_weight)
423
		})]
424
		pub fn approve_as_multi(
425
			origin: OriginFor<T>,
426
			threshold: u16,
427
			other_signatories: Vec<T::AccountId>,
428
			maybe_timepoint: Option<Timepoint<BlockNumberFor<T>>>,
429
			call_hash: [u8; 32],
430
			max_weight: Weight,
431
216
		) -> DispatchResultWithPostInfo {
432
216
			let who = ensure_signed(origin)?;
433
216
			Self::operate(
434
216
				who,
435
216
				threshold,
436
216
				other_signatories,
437
216
				maybe_timepoint,
438
216
				CallOrHash::Hash(call_hash),
439
216
				max_weight,
440
216
			)
441
		}
442

            
443
		/// Cancel a pre-existing, on-going multisig transaction. Any deposit reserved previously
444
		/// for this operation will be unreserved on success.
445
		///
446
		/// The dispatch origin for this call must be _Signed_.
447
		///
448
		/// - `threshold`: The total number of approvals for this dispatch before it is executed.
449
		/// - `other_signatories`: The accounts (other than the sender) who can approve this
450
		/// dispatch. May not be empty.
451
		/// - `timepoint`: The timepoint (block number and transaction index) of the first approval
452
		/// transaction for this dispatch.
453
		/// - `call_hash`: The hash of the call to be executed.
454
		///
455
		/// ## Complexity
456
		/// - `O(S)`.
457
		/// - Up to one balance-reserve or unreserve operation.
458
		/// - One passthrough operation, one insert, both `O(S)` where `S` is the number of
459
		///   signatories. `S` is capped by `MaxSignatories`, with weight being proportional.
460
		/// - One encode & hash, both of complexity `O(S)`.
461
		/// - One event.
462
		/// - I/O: 1 read `O(S)`, one remove.
463
		/// - Storage: removes one item.
464
		#[pallet::call_index(3)]
465
		#[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))]
466
		pub fn cancel_as_multi(
467
			origin: OriginFor<T>,
468
			threshold: u16,
469
			other_signatories: Vec<T::AccountId>,
470
			timepoint: Timepoint<BlockNumberFor<T>>,
471
			call_hash: [u8; 32],
472
117
		) -> DispatchResult {
473
117
			let who = ensure_signed(origin)?;
474
117
			ensure!(threshold >= 2, Error::<T>::MinimumThreshold);
475
78
			let max_sigs = T::MaxSignatories::get() as usize;
476
78
			ensure!(!other_signatories.is_empty(), Error::<T>::TooFewSignatories);
477
12
			ensure!(other_signatories.len() < max_sigs, Error::<T>::TooManySignatories);
478
12
			let signatories = Self::ensure_sorted_and_insert(other_signatories, who.clone())?;
479

            
480
3
			let id = Self::multi_account_id(&signatories, threshold);
481

            
482
3
			let m = <Multisigs<T>>::get(&id, call_hash).ok_or(Error::<T>::NotFound)?;
483
			ensure!(m.when == timepoint, Error::<T>::WrongTimepoint);
484
			ensure!(m.depositor == who, Error::<T>::NotOwner);
485

            
486
			let err_amount = T::Currency::unreserve(&m.depositor, m.deposit);
487
			debug_assert!(err_amount.is_zero());
488
			<Multisigs<T>>::remove(&id, &call_hash);
489

            
490
			Self::deposit_event(Event::MultisigCancelled {
491
				cancelling: who,
492
				timepoint,
493
				multisig: id,
494
				call_hash,
495
			});
496
			Ok(())
497
		}
498
	}
499
}
500

            
501
impl<T: Config> Pallet<T> {
502
	/// Derive a multi-account ID from the sorted list of accounts and the threshold that are
503
	/// required.
504
	///
505
	/// NOTE: `who` must be sorted. If it is not, then you'll get the wrong answer.
506
1209
	pub fn multi_account_id(who: &[T::AccountId], threshold: u16) -> T::AccountId {
507
1209
		let entropy = (b"modlpy/utilisuba", who, threshold).using_encoded(blake2_256);
508
1209
		Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
509
1209
			.expect("infinite length input; no invalid inputs for type; qed")
510
1209
	}
511

            
512
1746
	fn operate(
513
1746
		who: T::AccountId,
514
1746
		threshold: u16,
515
1746
		other_signatories: Vec<T::AccountId>,
516
1746
		maybe_timepoint: Option<Timepoint<BlockNumberFor<T>>>,
517
1746
		call_or_hash: CallOrHash<T>,
518
1746
		max_weight: Weight,
519
1746
	) -> DispatchResultWithPostInfo {
520
1746
		ensure!(threshold >= 2, Error::<T>::MinimumThreshold);
521
1041
		let max_sigs = T::MaxSignatories::get() as usize;
522
1041
		ensure!(!other_signatories.is_empty(), Error::<T>::TooFewSignatories);
523
453
		let other_signatories_len = other_signatories.len();
524
453
		ensure!(other_signatories_len < max_sigs, Error::<T>::TooManySignatories);
525
453
		let signatories = Self::ensure_sorted_and_insert(other_signatories, who.clone())?;
526

            
527
345
		let id = Self::multi_account_id(&signatories, threshold);
528

            
529
		// Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`.
530
345
		let (call_hash, call_len, maybe_call) = match call_or_hash {
531
306
			CallOrHash::Call(call) => {
532
408
				let (call_hash, call_len) = call.using_encoded(|d| (blake2_256(d), d.len()));
533
306
				(call_hash, call_len, Some(call))
534
			},
535
39
			CallOrHash::Hash(h) => (h, 0, None),
536
		};
537

            
538
		// Branch on whether the operation has already started or not.
539
345
		if let Some(mut m) = <Multisigs<T>>::get(&id, call_hash) {
540
			// Yes; ensure that the timepoint exists and agrees.
541
15
			let timepoint = maybe_timepoint.ok_or(Error::<T>::NoTimepoint)?;
542
			ensure!(m.when == timepoint, Error::<T>::WrongTimepoint);
543

            
544
			// Ensure that either we have not yet signed or that it is at threshold.
545
			let mut approvals = m.approvals.len() as u16;
546
			// We only bother with the approval if we're below threshold.
547
			let maybe_pos = m.approvals.binary_search(&who).err().filter(|_| approvals < threshold);
548
			// Bump approvals if not yet voted and the vote is needed.
549
			if maybe_pos.is_some() {
550
				approvals += 1;
551
			}
552

            
553
			// We only bother fetching/decoding call if we know that we're ready to execute.
554
			if let Some(call) = maybe_call.filter(|_| approvals >= threshold) {
555
				// verify weight
556
				ensure!(
557
					call.get_dispatch_info().weight.all_lte(max_weight),
558
					Error::<T>::MaxWeightTooLow
559
				);
560

            
561
				// Clean up storage before executing call to avoid an possibility of reentrancy
562
				// attack.
563
				<Multisigs<T>>::remove(&id, call_hash);
564
				T::Currency::unreserve(&m.depositor, m.deposit);
565

            
566
				let result = call.dispatch(RawOrigin::Signed(id.clone()).into());
567
				Self::deposit_event(Event::MultisigExecuted {
568
					approving: who,
569
					timepoint,
570
					multisig: id,
571
					call_hash,
572
					result: result.map(|_| ()).map_err(|e| e.error),
573
				});
574
				Ok(get_result_weight(result)
575
					.map(|actual_weight| {
576
						T::WeightInfo::as_multi_complete(
577
							other_signatories_len as u32,
578
							call_len as u32,
579
						)
580
						.saturating_add(actual_weight)
581
					})
582
					.into())
583
			} else {
584
				// We cannot dispatch the call now; either it isn't available, or it is, but we
585
				// don't have threshold approvals even with our signature.
586

            
587
				if let Some(pos) = maybe_pos {
588
					// Record approval.
589
					m.approvals
590
						.try_insert(pos, who.clone())
591
						.map_err(|_| Error::<T>::TooManySignatories)?;
592
					<Multisigs<T>>::insert(&id, call_hash, m);
593
					Self::deposit_event(Event::MultisigApproval {
594
						approving: who,
595
						timepoint,
596
						multisig: id,
597
						call_hash,
598
					});
599
				} else {
600
					// If we already approved and didn't store the Call, then this was useless and
601
					// we report an error.
602
					Err(Error::<T>::AlreadyApproved)?
603
				}
604

            
605
				let final_weight =
606
					T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32);
607
				// Call is not made, so the actual weight does not include call
608
				Ok(Some(final_weight).into())
609
			}
610
		} else {
611
			// Not yet started; there should be no timepoint given.
612
330
			ensure!(maybe_timepoint.is_none(), Error::<T>::UnexpectedTimepoint);
613

            
614
			// Just start the operation by recording it in storage.
615
291
			let deposit = T::DepositBase::get() + T::DepositFactor::get() * threshold.into();
616
291

            
617
291
			T::Currency::reserve(&who, deposit)?;
618

            
619
288
			let initial_approvals =
620
288
				vec![who.clone()].try_into().map_err(|_| Error::<T>::TooManySignatories)?;
621

            
622
288
			<Multisigs<T>>::insert(
623
288
				&id,
624
288
				call_hash,
625
288
				Multisig {
626
288
					when: Self::timepoint(),
627
288
					deposit,
628
288
					depositor: who.clone(),
629
288
					approvals: initial_approvals,
630
288
				},
631
288
			);
632
288
			Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash });
633
288

            
634
288
			let final_weight =
635
288
				T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32);
636
288
			// Call is not made, so the actual weight does not include call
637
288
			Ok(Some(final_weight).into())
638
		}
639
1746
	}
640

            
641
	/// The current `Timepoint`.
642
288
	pub fn timepoint() -> Timepoint<BlockNumberFor<T>> {
643
288
		Timepoint {
644
288
			height: <system::Pallet<T>>::block_number(),
645
288
			index: <system::Pallet<T>>::extrinsic_index().unwrap_or_default(),
646
288
		}
647
288
	}
648

            
649
	/// Check that signatories is sorted and doesn't contain sender, then insert sender.
650
1644
	fn ensure_sorted_and_insert(
651
1644
		other_signatories: Vec<T::AccountId>,
652
1644
		who: T::AccountId,
653
1644
	) -> Result<Vec<T::AccountId>, DispatchError> {
654
1644
		let mut signatories = other_signatories;
655
1644
		let mut maybe_last = None;
656
1644
		let mut index = 0;
657
3507
		for item in signatories.iter() {
658
3507
			if let Some(last) = maybe_last {
659
1863
				ensure!(last < item, Error::<T>::SignatoriesOutOfOrder);
660
1644
			}
661
3075
			if item <= &who {
662
948
				ensure!(item != &who, Error::<T>::SenderInSignatories);
663
945
				index += 1;
664
2127
			}
665
3072
			maybe_last = Some(item);
666
		}
667
1209
		signatories.insert(index, who);
668
1209
		Ok(signatories)
669
1644
	}
670
}
671

            
672
/// Return the weight of a dispatch call result as an `Option`.
673
///
674
/// Will return the weight regardless of what the state of the result is.
675
fn get_result_weight(result: DispatchResultWithPostInfo) -> Option<Weight> {
676
	match result {
677
		Ok(post_info) => post_info.actual_weight,
678
		Err(err) => err.post_info.actual_weight,
679
	}
680
}