Skip to content

Commit

Permalink
payment: allow paying from deposits
Browse files Browse the repository at this point in the history
* Add deposit field to Allocation:
  * deposit id and contract address
* Validate allocations with deposits by checking deposit status instead
  of the internal account balance.
* Make SchedulePayment deposit-aware.
  • Loading branch information
kamirr committed Jul 9, 2024
1 parent 64cdac0 commit 2ce3ab3
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 46 deletions.
16 changes: 7 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ members = [
# diesel 1.4.* supports up to 0.23.0, but sqlx 0.5.9 requires 0.22.0
# sqlx 0.5.10 need 0.23.2, so 0.5.9 is last version possible
derive_more = "0.99.11"
erc20_payment_lib = { git = "https://github.com/golemfactory/erc20_payment_lib", rev = "0304f7f3075b2a353c028370f56ddb83baf7581c" }
erc20_processor = { git = "https://github.com/golemfactory/erc20_payment_lib", rev = "0304f7f3075b2a353c028370f56ddb83baf7581c" }
erc20_payment_lib = { git = "https://github.com/golemfactory/erc20_payment_lib", rev = "d82a4e2031ec2f434e301190480b5522f371848b" }
erc20_processor = { git = "https://github.com/golemfactory/erc20_payment_lib", rev = "d82a4e2031ec2f434e301190480b5522f371848b" }
#erc20_payment_lib = { path = "../../payments/erc20_payment_lib/crates/erc20_payment_lib" }
#erc20_processor = { path = "../../payments/erc20_payment_lib" }
#erc20_payment_lib = { version = "=0.4.1" }
Expand Down Expand Up @@ -280,9 +280,9 @@ ya-service-api-interfaces = { path = "core/serv-api/interfaces" }
ya-service-api-web = { path = "core/serv-api/web" }

## CLIENT
#ya-client = { git = "https://github.com/golemfactory/ya-client.git", rev = "57dc4808f9db63ce20e4e7b799fd6a1613610d0a" }
ya-client = { git = "https://github.com/golemfactory/ya-client.git", rev = "e58208bdd521afbb626021d94b0b91a7d17d4e9d" }
#ya-client = { path = "../ya-client" }
#ya-client-model = { git = "https://github.com/golemfactory/ya-client.git", rev = "v0.7.0" }
ya-client-model = { git = "https://github.com/golemfactory/ya-client.git", rev = "e58208bdd521afbb626021d94b0b91a7d17d4e9d" }
#ya-client-model = "0.7"
golem-certificate = { git = "https://github.com/golemfactory/golem-certificate.git", rev = "f2d7514c18fc066e9cfb796090b90f5b27cfe1c6" }

Expand Down
14 changes: 13 additions & 1 deletion core/model/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt::Display;
use std::time::Duration;
use ya_client_model::payment::{Allocation, DriverStatusProperty, Payment};
use ya_client_model::payment::{allocation::Deposit, Allocation, DriverStatusProperty, Payment};
use ya_service_bus::RpcMessage;

pub fn driver_bus_id<T: Display>(driver_name: T) -> String {
Expand Down Expand Up @@ -316,6 +316,7 @@ pub struct SchedulePayment {
sender: String,
recipient: String,
platform: String,
deposit_id: Option<String>,
due_date: DateTime<Utc>,
}

Expand All @@ -325,13 +326,15 @@ impl SchedulePayment {
sender: String,
recipient: String,
platform: String,
deposit_id: Option<String>,
due_date: DateTime<Utc>,
) -> SchedulePayment {
SchedulePayment {
amount,
sender,
recipient,
platform,
deposit_id,
due_date,
}
}
Expand All @@ -352,6 +355,10 @@ impl SchedulePayment {
self.platform.clone()
}

pub fn deposit_id(&self) -> Option<String> {
self.deposit_id.clone()
}

pub fn due_date(&self) -> DateTime<Utc> {
self.due_date
}
Expand All @@ -370,6 +377,8 @@ pub struct ValidateAllocation {
pub address: String,
pub platform: String,
pub amount: BigDecimal,
pub timeout: Option<DateTime<Utc>>,
pub deposit: Option<Deposit>,
pub existing_allocations: Vec<Allocation>,
}

Expand All @@ -378,12 +387,15 @@ impl ValidateAllocation {
address: String,
platform: String,
amount: BigDecimal,
timeout: Option<DateTime<Utc>>,
existing: Vec<Allocation>,
) -> Self {
ValidateAllocation {
address,
platform,
amount,
timeout,
deposit: None,
existing_allocations: existing,
}
}
Expand Down
1 change: 1 addition & 0 deletions core/model/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ pub mod local {
pub platform: String,
pub address: String,
pub amount: BigDecimal,
pub timeout: Option<DateTime<Utc>>,
}

impl RpcMessage for ValidateAllocation {
Expand Down
131 changes: 104 additions & 27 deletions core/payment-driver/erc20/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::time::Instant;
use tokio::sync::mpsc::Receiver;
use uuid::Uuid;
use web3::types::{Address, H256};
use ya_client_model::payment::allocation::Deposit;
use ya_client_model::payment::DriverStatusProperty;
use ya_payment_driver::driver::IdentityError;

Expand Down Expand Up @@ -118,6 +119,7 @@ impl Erc20Driver {
amount: &BigDecimal,
network: &str,
deadline: Option<DateTime<Utc>>,
deposit_id: Option<String>,
) -> Result<String, GenericError> {
self.is_account_active(sender).await?;
let sender = H160::from_str(sender)
Expand All @@ -137,8 +139,7 @@ impl Erc20Driver {
amount,
payment_id: payment_id.clone(),
deadline,
allocation_id: None,
use_internal: false,
deposit_id,
})
.await
.map_err(|err| GenericError::new(format!("Error when inserting transfer {err:?}")))?;
Expand Down Expand Up @@ -270,6 +271,12 @@ impl Erc20Driver {
network,
})
}
LibStatusProperty::InvalidChainId { chain_id, .. } => {
Some(DriverStatusProperty::InvalidChainId {
driver: DRIVER_NAME.into(),
chain_id,
})
}
})
.collect())
}
Expand Down Expand Up @@ -354,6 +361,93 @@ impl Erc20Driver {
)
.await
}

async fn validate_allocation_internal(
&self,
caller: String,
msg: ValidateAllocation,
) -> Result<bool, GenericError> {
if msg.deposit.is_some() {
Err(GenericError::new(
"validate_allocation_internal called with not empty deposit",
))?;
}

let account_balance = self
.get_account_balance(
caller,
GetAccountBalance::new(msg.address, msg.platform.clone()),
)
.await?;

let total_allocated_amount: BigDecimal = msg
.existing_allocations
.into_iter()
.filter(|allocation| allocation.payment_platform == msg.platform)
.map(|allocation| allocation.remaining_amount)
.sum();

log::info!(
"Allocation validation: \
allocating: {:.5}, \
account_balance: {:.5}, \
total_allocated_amount: {:.5}",
msg.amount,
account_balance,
total_allocated_amount,
);

Ok(msg.amount <= account_balance - total_allocated_amount)
}

async fn validate_allocation_deposit(
&self,
msg: ValidateAllocation,
deposit: Deposit,
) -> Result<bool, GenericError> {
let network = msg
.platform
.split('-')
.nth(1)
.ok_or(GenericError::new(format!(
"Malformed platform string: {}",
msg.platform
)))?;

let deposit_details = self
.payment_runtime
.deposit_details(
network.to_string(),
U256::from_str(&deposit.id).unwrap(),
Address::from_str(&deposit.contract).unwrap(),
)
.await
.map_err(|e| GenericError::new(e))?;
let deposit_balance =
BigDecimal::new(BigInt::from_str(&deposit_details.amount).unwrap(), 18);

log::info!(
"Allocation validation with deposit: \
allocating: {:.5}, \
deposit balance: {:.5}, \
requested timeout: {}, \
deposit valid to: {}",
msg.amount,
deposit_balance,
msg.timeout
.map(|tm| tm.to_string())
.unwrap_or(String::from("never")),
deposit_details.valid_to,
);

let valid_amount = msg.amount <= deposit_balance;
let valid_timeout = msg
.timeout
.map(|timeout| timeout <= deposit_details.valid_to)
.unwrap_or(false);

Ok(valid_amount && valid_timeout)
}
}

#[async_trait(?Send)]
Expand Down Expand Up @@ -814,6 +908,7 @@ impl PaymentDriver for Erc20Driver {
&msg.amount,
&network,
Some(Utc::now()),
None,
)
.await
}
Expand All @@ -839,6 +934,7 @@ impl PaymentDriver for Erc20Driver {
&msg.amount(),
network,
Some(msg.due_date() - transfer_margin),
msg.deposit_id(),
)
.await
}
Expand Down Expand Up @@ -887,34 +983,15 @@ impl PaymentDriver for Erc20Driver {
async fn validate_allocation(
&self,
caller: String,
msg: ValidateAllocation,
mut msg: ValidateAllocation,
) -> Result<bool, GenericError> {
log::debug!("Validate_allocation: {:?}", msg);
let account_balance = self
.get_account_balance(
caller,
GetAccountBalance::new(msg.address, msg.platform.clone()),
)
.await?;

let total_allocated_amount: BigDecimal = msg
.existing_allocations
.into_iter()
.filter(|allocation| allocation.payment_platform == msg.platform)
.map(|allocation| allocation.remaining_amount)
.sum();

log::info!(
"Allocation validation: \
allocating: {:.5}, \
account_balance: {:.5}, \
total_allocated_amount: {:.5}",
msg.amount,
account_balance,
total_allocated_amount,
);

Ok(msg.amount <= account_balance - total_allocated_amount)
if let Some(deposit) = msg.deposit.take() {
self.validate_allocation_deposit(msg, deposit).await
} else {
self.validate_allocation_internal(caller, msg).await
}
}

async fn status(
Expand Down
2 changes: 2 additions & 0 deletions core/payment/examples/debit_note_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ async fn main() -> anyhow::Result<()> {
address: None, // Use default address (i.e. identity)
payment_platform: Some(PaymentPlatformEnum::PaymentPlatformName(args.platform)),
total_amount: BigDecimal::from(10u64),
timeout: None,
make_deposit: false,
deposit: None,
timeout: None,
make_deposit: false,
})
.await?;
log::info!("Allocation created.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE pay_allocation REMOVE COLUMN deposit;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE pay_allocation ADD COLUMN deposit TEXT DEFAULT NULL;
2 changes: 2 additions & 0 deletions core/payment/src/api/allocations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ async fn create_allocation(
platform: payment_triple.to_string(),
address: address.clone(),
amount: allocation.total_amount.clone(),
timeout: allocation.timeout,
};

match async move { Ok(bus::service(LOCAL_SERVICE).send(validate_msg).await??) }.await {
Expand Down Expand Up @@ -488,6 +489,7 @@ async fn amend_allocation(
} else {
0.into()
},
timeout: amended_allocation.timeout,
};
match async move { Ok(bus::service(LOCAL_SERVICE).send(validate_msg).await??) }.await {
Ok(true) => {}
Expand Down
Loading

0 comments on commit 2ce3ab3

Please sign in to comment.