Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIL-227] Automatic allocator #225

Merged
merged 11 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,193 changes: 146 additions & 2,047 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions fplus-database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,5 @@ serde = { version = "1.0.164", features = ["derive", "std",
serial_test = "3.0.0"
sha1 = "0.10.6"
serde_json = "1.0.96"
alloy = { git = "https://github.com/alloy-rs/alloy", version = "0.3.2", features = [
"signers",
] }
alloy = { version = "0.3.2", features = ["signers"] }
sea-orm-newtype = "0.0.1"
57 changes: 43 additions & 14 deletions fplus-database/src/database/autoallocations.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::get_database_connection;
use crate::models::autoallocations::AddressWrapper;
use crate::models::autoallocations::{ActiveModel, Column, Entity as Autoallocations};
use chrono::{DateTime, FixedOffset, Utc};
use sea_orm::{entity::*, query::*, DbErr};
use crate::models::autoallocations::{
Column, Entity as Autoallocations, Model as AutoallocationModel,
};
use alloy::primitives::Address;
use chrono::{DateTime, FixedOffset};
use sea_orm::{entity::*, query::*, DbBackend, DbErr, ExecResult};

pub async fn get_last_client_autoallocation(
client_evm_address: impl Into<AddressWrapper>,
Expand All @@ -17,19 +20,45 @@ pub async fn get_last_client_autoallocation(
}

pub async fn create_or_update_autoallocation(
client_evm_address: impl Into<AddressWrapper> + Clone,
) -> Result<(), sea_orm::DbErr> {
client_evm_address: &Address,
days_to_next_autoallocation: &u64,
) -> Result<u64, sea_orm::DbErr> {
let conn = get_database_connection().await?;
let last_autoallocation = get_last_client_autoallocation(client_evm_address.clone()).await?;
let client_address = client_evm_address.to_checksum(None);
let exec_res: ExecResult = conn
.execute(Statement::from_string(
DbBackend::Postgres,
format!(
"INSERT INTO autoallocations (evm_wallet_address, last_allocation)
VALUES ('{}', NOW())
ON CONFLICT (evm_wallet_address)
DO UPDATE SET last_allocation = NOW()
WHERE autoallocations.last_allocation <= NOW() - INTERVAL '{} days';",
client_address, days_to_next_autoallocation
),
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
))
.await?;
Ok(exec_res.rows_affected())
}

pub async fn get_autoallocation(
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
client_evm_address: impl Into<AddressWrapper>,
) -> Result<Option<AutoallocationModel>, DbErr> {
let conn = get_database_connection().await?;
let response = Autoallocations::find()
.filter(Column::EvmWalletAddress.contains(client_evm_address.into()))
.one(&conn)
.await?;
Ok(response)
}

let autoallocation_active_model = ActiveModel {
evm_wallet_address: Set(client_evm_address.into()),
last_allocation: Set(Utc::now().into()),
};
if last_autoallocation.is_some() {
autoallocation_active_model.update(&conn).await?;
} else {
autoallocation_active_model.insert(&conn).await?;
pub async fn delete_autoallocation(
client_evm_address: impl Into<AddressWrapper>,
) -> Result<(), sea_orm::DbErr> {
let conn = get_database_connection().await?;
let client_autoallocation = get_autoallocation(client_evm_address).await?;
if let Some(client_autoallocation) = client_autoallocation {
client_autoallocation.delete(&conn).await?;
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
}
Ok(())
}
1 change: 0 additions & 1 deletion fplus-http-server/src/router/autoallocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use actix_web::{get, post, web, HttpResponse, Responder};
use fplus_database::database::autoallocations as autoallocations_db;
use fplus_lib::core::autoallocator;
use fplus_lib::core::{LastAutoallocationQueryParams, TriggerAutoallocationInfo};

#[get("/autoallocator/last_client_allocation")]
pub async fn last_client_allocation(
query: web::Query<LastAutoallocationQueryParams>,
Expand Down
2 changes: 1 addition & 1 deletion fplus-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ regex = "1.0"
tempfile = "3.10.1"
size = "0.5.0-preview2"
alloy = { version = "0.3.2", features = ["full"] }
fvm = "4.4.0"
fvm_shared = "4.4.0"

[dev-dependencies]
actix-rt = "2.9.0"
Expand Down
7 changes: 3 additions & 4 deletions fplus-lib/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn default_env_vars() -> &'static HashMap<&'static str, &'static str> {
"https://fp-core.dp04sa0tdc6pk.us-east-1.cs.amazonlightsail.com",
);
m.insert("FILPLUS_ENV", "staging");
m.insert("GLIF_NODE_URL", "https://api.node.glif.io/rpc/v1");
m.insert("GLIF_NODE_URL", "http://localhost:1234/rpc/v1");
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
m.insert("ISSUE_TEMPLATE_VERSION", "1.3");
m.insert(
"GITCOIN_PASSPORT_DECODER",
Expand All @@ -36,16 +36,15 @@ pub fn default_env_vars() -> &'static HashMap<&'static str, &'static str> {
m.insert("DMOB_API_URL", "https://api.datacapstats.io/public/api");
m.insert("DMOB_API_KEY", "5c993a17-7b18-4ead-a8a8-89dad981d87e");
m.insert("DAYS_TO_NEXT_AUTOALLOCATION", "14");
m.insert("FILECOIN_RPC_URL", "http://127.0.0.1:8545");
m.insert(
"ALLOCATOR_CONTRACT_ADDRESS",
"0x640bD4be149f40714D95aBcD414338bc7CfF39a3",
);
m.insert(
"PRIVATE_KEY",
"AUTOALLOCATOR_PRIVATE_KEY",
"257d553b55d5928c7ec48c2f7d1288931640166e2c1269e05492914accf7e966",
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
);
m.insert("AMOUNT_TO_AUTOALLOCATION", "68719476736"); // 68719476736 B == 64 GB
m.insert("AUTOALLOCATION_AMOUNT", "68719476736"); // 68719476736 B == 64 GB
m
})
}
Expand Down
20 changes: 10 additions & 10 deletions fplus-lib/src/core/application/gitcoin_interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::error::LDNError;
use anyhow::Result;

pub trait ExpirableSolStruct: SolStruct {
fn get_expires_at(&self) -> String;
fn get_issued_at(&self) -> String;
fn get_expires_at(&self) -> &str;
fn get_issued_at(&self) -> &str;
}

sol! {
Expand All @@ -44,22 +44,22 @@ sol! {
}

impl ExpirableSolStruct for KycApproval {
fn get_expires_at(&self) -> String {
self.expires_at.clone()
fn get_expires_at(&self) -> &str {
&self.expires_at
}

fn get_issued_at(&self) -> String {
self.issued_at.clone()
fn get_issued_at(&self) -> &str {
&self.issued_at
}
}

impl ExpirableSolStruct for KycAutoallocationApproval {
fn get_expires_at(&self) -> String {
self.expires_at.clone()
fn get_expires_at(&self) -> &str {
&self.expires_at
}

fn get_issued_at(&self) -> String {
self.issued_at.clone()
fn get_issued_at(&self) -> &str {
&self.issued_at
}
}

Expand Down
24 changes: 16 additions & 8 deletions fplus-lib/src/core/autoallocator/metaallocator_interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ use alloy::{
sol_types::SolCall,
};
use anyhow::Result;
use fvm::kernel::prelude::Address as FilecoinAddress;
use fvm_shared::address::{set_current_network, Address as FilecoinAddress, Network};
sol! {
#[allow(missing_docs)]
function addVerifiedClient(bytes calldata clientAddress, uint256 amount);
}

pub async fn add_verified_client(address: &String, amount: &u64) -> Result<(), LDNError> {
let private_key = get_env_var_or_default("PRIVATE_KEY");
pub async fn add_verified_client(address: &str, amount: &u64) -> Result<(), LDNError> {
let private_key = get_env_var_or_default("AUTOALLOCATOR_PRIVATE_KEY");
let signer: PrivateKeySigner = private_key.parse().expect("Should parse private key");
let wallet = EthereumWallet::from(signer);
let rpc_url = get_env_var_or_default("FILECOIN_RPC_URL")
let rpc_url = get_env_var_or_default("GLIF_NODE_URL")
.parse()
.map_err(|e| LDNError::New(format!("Failed to pase string to URL /// {}", e)))?;
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.on_http(rpc_url);
let fil_address_bytes = get_filecoin_address_from_string_to_bytes(address)?;
let amount = U256::try_from(amount.clone())
let fil_address = decode_filecoin_address(address)?;
let amount = U256::try_from(*amount)
.map_err(|e| LDNError::New(format!("Failed to prase amount to U256 /// {}", e)))?;
let call = addVerifiedClientCall {
clientAddress: fil_address_bytes.into(),
clientAddress: fil_address.into(),
amount,
}
.abi_encode();
Expand Down Expand Up @@ -62,7 +62,15 @@ pub async fn add_verified_client(address: &String, amount: &u64) -> Result<(), L
Ok(())
}

fn get_filecoin_address_from_string_to_bytes(address: &str) -> Result<Vec<u8>, LDNError> {
fn decode_filecoin_address(address: &str) -> Result<Vec<u8>, LDNError> {
let address_prefix = address.get(0..1);
if let Some(address_prefix) = address_prefix {
if address_prefix.eq("f") {
set_current_network(Network::Mainnet);
} else if address_prefix.eq("t") {
set_current_network(Network::Testnet);
}
}
let fil_address = FilecoinAddress::from_str(address)
.map_err(|e| LDNError::New(format!("Failed to prase address from string /// {}", e)))?;
Ok(fil_address.to_bytes())
Expand Down
68 changes: 33 additions & 35 deletions fplus-lib/src/core/autoallocator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::core::verify_on_gitcoin;
use crate::core::{LDNApplication, TriggerAutoallocationInfo};
use crate::error::LDNError;
use alloy::primitives::Address;
use chrono::{Duration, Utc};
use fplus_database::database::applications::get_applications_by_client_id;
use fplus_database::database::autoallocations as autoallocations_db;

Expand All @@ -13,58 +12,57 @@ pub mod metaallocator_interaction;
pub async fn trigger_autoallocation(info: &TriggerAutoallocationInfo) -> Result<(), LDNError> {
let evm_address_from_signature =
LDNApplication::verify_kyc_data_and_get_eth_address(&info.message, &info.signature)?;
autoallocation_timeout_exceeded(&evm_address_from_signature).await?;
verify_on_gitcoin(&evm_address_from_signature).await?;
let fil_client_address = &info.message.client_fil_address;
let client_applications = get_applications_by_client_id(fil_client_address)
.await
.map_err(|e| LDNError::Load(format!("Get applications for client failed: {}", e)))?;
if client_applications.len() != 0 {
if !client_applications.is_empty() {
return Err(LDNError::Load(
"Cient already has an application".to_string(),
"Client already has an application".to_string(),
));
}

let amount = get_env_var_or_default("AMOUNT_TO_AUTOALLOCATION")
let amount = get_env_var_or_default("AUTOALLOCATION_AMOUNT")
.parse::<u64>()
.map_err(|e| {
LDNError::New(format!(
"Parse days to next allocation to i64 failed: {}",
e
))
})?;
add_verified_client(&fil_client_address, &amount).await?;
autoallocations_db::create_or_update_autoallocation(evm_address_from_signature.clone())
.await
.map_err(|e| LDNError::New(format!("Create or update autoallocation failed: {}", e)))?;
create_or_update_autoallocation(&evm_address_from_signature).await?;
match add_verified_client(fil_client_address, &amount).await {
Ok(_) => {}
Err(e) => {
autoallocations_db::delete_autoallocation(evm_address_from_signature)
.await
.map_err(|e| LDNError::New(format!("Delete autoallocation failed: {}", e)))?;
return Err(LDNError::New(format!("Add verified client failed: {}", e)));
}
}
Ok(())
}

async fn autoallocation_timeout_exceeded(
evm_address_from_signature: &Address,
) -> Result<(), LDNError> {
let last_client_allocation =
autoallocations_db::get_last_client_autoallocation(evm_address_from_signature.clone())
.await
.map_err(|e| {
LDNError::Load(format!("Failed to get last client allocation /// {}", e))
})?;

if let Some(last_client_allocation) = last_client_allocation {
let days_to_next_autoallocation = get_env_var_or_default("DAYS_TO_NEXT_AUTOALLOCATION")
.parse::<i64>()
.map_err(|e| {
LDNError::New(format!(
"Parse days to next allocation to i64 failed: {}",
e
))
})?;
if (last_client_allocation + Duration::days(days_to_next_autoallocation)) > Utc::now() {
return Err(LDNError::Load(format!(
"Last allocation was within {} days.",
days_to_next_autoallocation
)));
}
async fn create_or_update_autoallocation(evm_client_address: &Address) -> Result<(), LDNError> {
kacperzuk-neti marked this conversation as resolved.
Show resolved Hide resolved
let days_to_next_autoallocation = get_env_var_or_default("DAYS_TO_NEXT_AUTOALLOCATION")
.parse::<u64>()
.map_err(|e| {
LDNError::New(format!(
"Parse days to next allocation to u64 failed: {}",
e
))
})?;
let rows_affected = autoallocations_db::create_or_update_autoallocation(
evm_client_address,
&days_to_next_autoallocation,
)
.await
.map_err(|e| LDNError::New(format!("Create or update autoallocation failed: {}", e)))?;
if rows_affected == 0 {
return Err(LDNError::Load(format!(
"Last allocation was within {} days.",
days_to_next_autoallocation
)));
}
Ok(())
}
4 changes: 2 additions & 2 deletions fplus-lib/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4027,13 +4027,13 @@ _The initial issue can be edited in order to solve the request of the verifier.
let address_from_signature = get_address_from_signature(message, signature)?;

let current_timestamp = Local::now();
if LDNApplication::date_is_expired(&message.get_expires_at(), &current_timestamp)? {
if LDNApplication::date_is_expired(message.get_expires_at(), &current_timestamp)? {
return Err(LDNError::Load(format!(
"Message expired at {}",
message.get_expires_at()
)));
}
if LDNApplication::date_is_from_future(&message.get_issued_at(), &current_timestamp)? {
if LDNApplication::date_is_from_future(message.get_issued_at(), &current_timestamp)? {
return Err(LDNError::Load(format!(
"Message issued date {} is from future",
message.get_issued_at()
Expand Down