diff --git a/Cargo.toml b/Cargo.toml
index d1253fc5b0cb9e6302e4a47d7188888250c12e8d..f1c6474bd731c2b1e33e7dd1ea2810218a03be87 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2018"
 [dependencies]
 serenity = "0.6.3"
 rand = "0.7.0"
+lazy_static = "1.3.0"
diff --git a/src/main.rs b/src/main.rs
index e4c67b4c5e4dca7473dcccb40f6d5b6a3a44c60c..e5d7a1c1187b20f10c71727f9b0041d641bccac1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,6 @@
+#[macro_use]
+extern crate lazy_static;
+
 use serenity::{
     model::{channel, channel::Message, gateway::Ready, guild::Member},
     prelude::*,
diff --git a/src/voting.rs b/src/voting.rs
index 2960c0f2c68972b67cd8238287938a2746ed14ff..3a6363e9d1d82512d3d6fc994079d25e0f41bc80 100644
--- a/src/voting.rs
+++ b/src/voting.rs
@@ -3,6 +3,8 @@ use serenity::{
     prelude::*,
     utils::MessageBuilder,
 };
+use std::collections::HashMap;
+use std::sync::Mutex;
 
 use crate::config;
 
@@ -77,6 +79,9 @@ impl Commands {
 
 fn create_motion(ctx: &Context, msg: &Message, topic: &str) {
     println!("{} created a motion {}", msg.author.name, topic);
+    if let Err(why) = msg.delete(ctx) {
+        println!("Error deleting motion prompt: {:?}", why);
+    }
     match msg.channel_id.send_message(&ctx.http, |m| {
         m.embed(|embed| {
             embed.author(|a| {
@@ -110,13 +115,9 @@ fn create_motion(ctx: &Context, msg: &Message, topic: &str) {
         m
     }) {
         Err(why) => {
-            println!("Error sending message: {:?}", why);
-        }
-        Ok(_) => {
-            if let Err(why) = msg.delete(ctx) {
-                println!("Error deleting motion prompt: {:?}", why);
-            }
+            println!("Error creating motion: {:?}", why);
         }
+        Ok(_) => {}
     }
 }
 
@@ -160,6 +161,53 @@ fn create_poll(ctx: &Context, msg: &Message, topic: &str) {
     }
 }
 
+#[derive(Debug, Clone)]
+struct MotionInfo {
+    votes: HashMap<&'static str, Vec<serenity::model::user::User>>,
+}
+
+lazy_static! {
+    static ref MOTIONS_CACHE: Mutex<HashMap<serenity::model::id::MessageId, MotionInfo>> =
+        Mutex::new(HashMap::new());
+}
+
+fn get_cached_motion(ctx: &Context, msg: &Message) -> MotionInfo {
+    let mut cached_motions = MOTIONS_CACHE.lock().unwrap();
+    if !cached_motions.contains_key(&msg.id) {
+        println!("Initialising representation of motion {:?}", msg.id);
+        let this_motion = MotionInfo {
+            votes: {
+                let mut m = HashMap::new();
+                m.insert(
+                    config::FOR_VOTE,
+                    msg.reaction_users(ctx, config::FOR_VOTE, None, None)
+                        .unwrap(),
+                );
+                m.insert(
+                    config::AGAINST_VOTE,
+                    msg.reaction_users(ctx, config::AGAINST_VOTE, None, None)
+                        .unwrap(),
+                );
+                m.insert(
+                    config::ABSTAIN_VOTE,
+                    msg.reaction_users(ctx, config::ABSTAIN_VOTE, None, None)
+                        .unwrap(),
+                );
+                m
+            },
+        };
+        cached_motions.insert(msg.id, this_motion);
+    }
+    return (*cached_motions.get(&msg.id).unwrap()).clone();
+}
+fn set_cached_motion(id: &serenity::model::id::MessageId, motion_info: MotionInfo) {
+    if let Some(motion) = MOTIONS_CACHE.lock().unwrap().get_mut(id) {
+        *motion = motion_info;
+    } else {
+        println!("{}", "Couldn't find motion in cache to set");
+    }
+}
+
 fn update_motion(
     ctx: &Context,
     msg: &mut Message,
@@ -167,50 +215,33 @@ fn update_motion(
     change: &str,
     reaction: channel::Reaction,
 ) {
-    let for_votes = msg
-        .reaction_users(ctx, config::FOR_VOTE, None, None)
-        .unwrap()
-        .len() as isize
-        - 1;
-    let against_votes = msg
-        .reaction_users(ctx, config::AGAINST_VOTE, None, None)
-        .unwrap()
-        .len() as isize
-        - 1;
-    let abstain_votes = msg
-        .reaction_users(ctx, config::ABSTAIN_VOTE, None, None)
-        .unwrap()
-        .len() as isize
-        - 1;
+    let motion_info: MotionInfo = get_cached_motion(ctx, msg);
+
+    let for_votes = motion_info.votes.get(config::FOR_VOTE).unwrap().len() as isize - 1;
+    let against_votes = motion_info.votes.get(config::AGAINST_VOTE).unwrap().len() as isize - 1;
+    let abstain_votes = motion_info.votes.get(config::ABSTAIN_VOTE).unwrap().len() as isize - 1;
 
-    let strength_buff = |react: &str| {
-        msg.reaction_users(ctx, react, None, None)
-            .unwrap()
-            .iter()
-            .filter(
-                |u| match u.has_role(ctx, config::SERVER_ID, config::TIEBREAKER_ROLE) {
-                    Ok(true) => true,
-                    _ => false,
-                },
-            )
-            .count()
-            > 0
+    let has_tiebreaker = |users: &Vec<serenity::model::user::User>| {
+        users.iter().any(|u| {
+            u.has_role(ctx, config::SERVER_ID, config::TIEBREAKER_ROLE)
+                .unwrap()
+        })
     };
 
     let for_strength = for_votes as f32
-        + (if strength_buff(config::FOR_VOTE) {
+        + (if has_tiebreaker(motion_info.votes.get(config::FOR_VOTE).unwrap()) {
             0.5
         } else {
             0.0
         });
     let against_strength = against_votes as f32
-        + (if strength_buff(config::AGAINST_VOTE) {
+        + (if has_tiebreaker(motion_info.votes.get(config::AGAINST_VOTE).unwrap()) {
             0.5
         } else {
             0.0
         });
     let abstain_strength = abstain_votes as f32
-        + (if strength_buff(config::ABSTAIN_VOTE) {
+        + (if has_tiebreaker(motion_info.votes.get(config::ABSTAIN_VOTE).unwrap()) {
             0.5
         } else {
             0.0
@@ -341,6 +372,15 @@ pub fn reaction_add(ctx: Context, add_reaction: channel::Reaction) {
                                 return;
                             }
                             if user.id.0 != config::BOT_ID {
+                                let mut motion_info = get_cached_motion(&ctx, &message);
+                                if let Some(vote) = motion_info
+                                    .votes
+                                    .get_mut(add_reaction.emoji.as_data().as_str())
+                                {
+                                    vote.retain(|u| u.id != user.id);
+                                    vote.push(user.clone());
+                                }
+                                set_cached_motion(&message.id, motion_info);
                                 update_motion(&ctx, &mut message, &user, "add", add_reaction);
                             }
                         }
@@ -374,6 +414,14 @@ pub fn reaction_remove(ctx: Context, removed_reaction: channel::Reaction) {
         Ok(mut message) => {
             if message.author.id.0 == config::BOT_ID {
                 if let Ok(user) = removed_reaction.user(&ctx) {
+                    let mut motion_info = get_cached_motion(&ctx, &message);
+                    if let Some(vote) = motion_info
+                        .votes
+                        .get_mut(removed_reaction.emoji.as_data().as_str())
+                    {
+                        vote.retain(|u| u.id != user.id);
+                    }
+                    set_cached_motion(&message.id, motion_info);
                     update_motion(&ctx, &mut message, &user, "remove", removed_reaction);
                 }
             }