diff --git a/entities/src/user.rs b/entities/src/user.rs
index 1cbe7815..ee957c0b 100644
--- a/entities/src/user.rs
+++ b/entities/src/user.rs
@@ -4,7 +4,7 @@ use crate::serialization;
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Hash, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key)]
diff --git a/web3_proxy/src/balance.rs b/web3_proxy/src/balance.rs
index b9f03a9b..4db43ea5 100644
--- a/web3_proxy/src/balance.rs
+++ b/web3_proxy/src/balance.rs
@@ -62,6 +62,8 @@ impl Balance {
}
pub fn was_ever_premium(&self) -> bool {
+ // TODO: technically we should also check that user_tier.downgrade_tier_id.is_some()
+ // but now we set premium automatically on deposit, so its fine for now
self.user_id != 0 && self.total_deposits() >= Decimal::from(10)
}
diff --git a/web3_proxy/src/caches.rs b/web3_proxy/src/caches.rs
index ebc1e291..ab5c7695 100644
--- a/web3_proxy/src/caches.rs
+++ b/web3_proxy/src/caches.rs
@@ -4,7 +4,7 @@ use crate::frontend::authorization::{AuthorizationChecks, RpcSecretKey};
use derive_more::From;
use entities::rpc_key;
use migration::sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter};
-use moka::future::{Cache, ConcurrentCacheExt};
+use moka::future::Cache;
use std::fmt;
use std::net::IpAddr;
use std::sync::Arc;
diff --git a/web3_proxy/src/frontend/admin.rs b/web3_proxy/src/frontend/admin.rs
index 286fb63f..a8064858 100644
--- a/web3_proxy/src/frontend/admin.rs
+++ b/web3_proxy/src/frontend/admin.rs
@@ -6,6 +6,7 @@ use crate::app::Web3ProxyApp;
use crate::errors::Web3ProxyResponse;
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext};
use crate::frontend::users::authentication::PostLogin;
+use crate::premium::{get_user_and_tier_from_address, grant_premium_tier};
use crate::user_token::UserBearerToken;
use axum::{
extract::{Path, Query},
@@ -65,14 +66,16 @@ pub async fn admin_increase_balance(
.await?
.ok_or_else(|| Web3ProxyError::AccessDenied("not an admin".into()))?;
- let user_entry: user::Model = user::Entity::find()
- .filter(user::Column::Address.eq(payload.user_address.as_bytes()))
- .one(&txn)
+ let (user_entry, user_tier_entry) = get_user_and_tier_from_address(&payload.user_address, &txn)
.await?
.ok_or(Web3ProxyError::BadRequest(
format!("No user found with {:?}", payload.user_address).into(),
))?;
+ grant_premium_tier(&user_entry, user_tier_entry.as_ref(), &txn)
+ .await
+ .web3_context("granting premium tier")?;
+
let increase_balance_receipt = admin_increase_balance_receipt::ActiveModel {
amount: sea_orm::Set(payload.amount),
admin_id: sea_orm::Set(admin_entry.id),
@@ -81,6 +84,7 @@ pub async fn admin_increase_balance(
..Default::default()
};
increase_balance_receipt.save(&txn).await?;
+
txn.commit().await?;
// Invalidate the user_balance_cache for this user:
diff --git a/web3_proxy/src/frontend/users/payment.rs b/web3_proxy/src/frontend/users/payment.rs
index 97173489..eb22314f 100644
--- a/web3_proxy/src/frontend/users/payment.rs
+++ b/web3_proxy/src/frontend/users/payment.rs
@@ -1,10 +1,11 @@
use crate::app::Web3ProxyApp;
use crate::balance::Balance;
-use crate::errors::{Web3ProxyError, Web3ProxyResponse, Web3ProxyResult};
+use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse, Web3ProxyResult};
use crate::frontend::authorization::{
login_is_authorized, Authorization as Web3ProxyAuthorization,
};
use crate::frontend::users::authentication::register_new_user;
+use crate::premium::grant_premium_tier;
use anyhow::Context;
use axum::{
extract::Path,
@@ -16,7 +17,7 @@ use axum_client_ip::InsecureClientIp;
use axum_macros::debug_handler;
use entities::{
admin_increase_balance_receipt, increase_on_chain_balance_receipt,
- stripe_increase_balance_receipt, user,
+ stripe_increase_balance_receipt, user, user_tier,
};
use ethers::abi::AbiEncode;
use ethers::types::{Address, Block, TransactionReceipt, TxHash, H256};
@@ -302,6 +303,8 @@ pub async fn user_balance_post(
// TODO: check bloom filters
+ let mut user_ids_need_premium = HashSet::new();
+
// the transaction might contain multiple relevant logs. collect them all
let mut response_data = vec![];
let mut user_ids_to_invalidate = HashSet::new();
@@ -405,9 +408,21 @@ pub async fn user_balance_post(
debug!("deposit data: {:#?}", x);
response_data.push(x);
+
+ user_ids_need_premium.insert(recipient);
}
}
+ for user in user_ids_need_premium.into_iter() {
+ let user_tier = user_tier::Entity::find_by_id(user.user_tier_id)
+ .one(&txn)
+ .await?;
+
+ grant_premium_tier(&user, user_tier.as_ref(), &txn)
+ .await
+ .web3_context("granting premium tier")?;
+ }
+
txn.commit().await?;
for user_id in user_ids_to_invalidate.into_iter() {
diff --git a/web3_proxy/src/frontend/users/payment_stripe.rs b/web3_proxy/src/frontend/users/payment_stripe.rs
index 9a4dcd28..819e58a1 100644
--- a/web3_proxy/src/frontend/users/payment_stripe.rs
+++ b/web3_proxy/src/frontend/users/payment_stripe.rs
@@ -1,5 +1,6 @@
use crate::app::Web3ProxyApp;
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
+use crate::premium::grant_premium_tier;
use anyhow::Context;
use axum::{
headers::{authorization::Bearer, Authorization},
@@ -7,7 +8,7 @@ use axum::{
Extension, Json, TypedHeader,
};
use axum_macros::debug_handler;
-use entities::{stripe_increase_balance_receipt, user};
+use entities::{stripe_increase_balance_receipt, user, user_tier};
use ethers::types::Address;
use http::HeaderMap;
use migration::sea_orm::prelude::Decimal;
@@ -163,6 +164,14 @@ pub async fn user_balance_stripe_post(
Some(recipient) => {
let _ = insert_receipt_model.save(&txn).await;
+ let user_tier = user_tier::Entity::find_by_id(recipient.user_tier_id)
+ .one(&txn)
+ .await?;
+
+ grant_premium_tier(&recipient, user_tier.as_ref(), &txn)
+ .await
+ .web3_context("granting premium tier")?;
+
txn.commit().await?;
// Finally invalidate the cache as well
diff --git a/web3_proxy/src/lib.rs b/web3_proxy/src/lib.rs
index d4744dea..6919a8b8 100644
--- a/web3_proxy/src/lib.rs
+++ b/web3_proxy/src/lib.rs
@@ -14,6 +14,7 @@ pub mod frontend;
pub mod http_params;
pub mod jsonrpc;
pub mod pagerduty;
+pub mod premium;
pub mod prometheus;
pub mod referral_code;
pub mod relational_db;
diff --git a/web3_proxy/src/premium.rs b/web3_proxy/src/premium.rs
new file mode 100644
index 00000000..a0828755
--- /dev/null
+++ b/web3_proxy/src/premium.rs
@@ -0,0 +1,64 @@
+use crate::errors::Web3ProxyResult;
+use anyhow::Context;
+use entities::{user, user_tier};
+use ethers::prelude::Address;
+use migration::sea_orm::{
+ self, ActiveModelTrait, ColumnTrait, DatabaseTransaction, EntityTrait, IntoActiveModel,
+ QueryFilter,
+};
+use tracing::info;
+
+pub async fn get_user_and_tier_from_address(
+ user_address: &Address,
+ txn: &DatabaseTransaction,
+) -> Web3ProxyResult